I hate Camtasia

I try not to over-react but I have come to detest Camtasia. Every time anyone at my company creates a video and puts it up on the web, it does not run in Internet Explorer. And then 2 people have to spend several hours figuring out how to make it work.

Every single time.

The original version we bought years ago (which you can no longer get) worked great. But since then - nothing but problems. Including some versions where the video would take 45 seconds to start playing. Do you wait 45 seconds for a video? 

Anyone know of a product that works? Because we can't afford to use a product that requires this level of effort to produce each video.

Verizon & Blackberry == awful squared

My wife decided to get a new Blackberry phone. We have Exchange at home (what can I say, I'm a nerd) and so she told them on purchasing that it must connect to Exchange's ActiveSync so it synchronizes her email, contacts, and calender. And at the Verizon store they said - yes, no problem.

  1. So I go to options to set email and... no option for Exchange. I call Verizon and get passed to two different people where I'm told to use IMAP. When I explain that no, we want ActiveSync we get passed over to BlackBerry where after a longer wait I am told that you don't set up ActiveSync connections in email btu instead in advanced options. Ok, so 25 minutes and 4 people to find that out.
  2. So I try that and this is where I start to learn that BlackBerry essentially has no error messages. It tries to connect and if it fails, after 25 minutes, pops up a message saying there was a problem and see your system administrator. I am my system administrator - what earthly use is a message like that?
  3. So call Verizon again where we are passed through to BlackBerry where they then dive in and discover... that my wife's account did not include enterprise access. So the idiot at the Verizon store (is "idiot" redundant?), told that she wanted enterprise access, did not include it in her plan. And the idiot at BlackBerry (redundant again?) the first time did not notice that she did not have enterprise access on her account.
  4. So we get all that set and now we're going to... Get the same stupid error again. Ok, this time I get forwarded to BlackBerry tier 2 support (which means an additional 38 minute wait) because tier 1 support has no idea what to do. And tier 2 support, after 10 minutes of asking me a bunch of questions and checking some stuff then tells me that... We have to install BlackBerry software on our server.

Yep, that's right, BlackBerry requires software on our mail server. Which I then have to learn how to configure & administer. And assuming that it is as poorly written as their setup code on the BlackBerry, that could end up being a full-time job.

So I figured that instead we will go with a company that understands how to write usable software. I connected my iPhone and my daughter's iPod to Exchange in under 2 minutes each. My wife will return the BlackBerry to Verizon on Monday and switch to an iPhone & AT&T.

And to the CEO at Verizon who has that nice message at the start of the customer service call - no I did not get what I needed. Not once in any of the 4 calls. If you want to get enterprise level customers, get an enterprise quality product. And that is not BlackBerry.

Got an opinion on charting UIs?

If so, please go to my post asking for suggestions on how to improve the charting UI in AutoTag.

thanks - dave

XmlZipResolver - an XmlUrlResolver for files in a zip file

In the java world a file you can pass a filename of "zip:MyStuff.zip!MyData.xml" and it then handles the MyData.xml file as the xml file to read. The attached file here does the same thing on the .NET side by providing a XmlUrlResolver derived class to handle this case.

This code was about 95% the code from http://news.oreilly.com/XmlZipResolver.cs where I cleaned it up a little and fixed a couple of subtle bugs.

Just use this class instead of XmlUrlResolver. You can use it for all cases because it calls XmlUrlResolver if the url does not start with zip: or jar:. Hopefully Microsoft will just add this in to XmlUrlResolver in the future.

Download XmlZipResolver

Opening an XML file that requires a username & password

So you need to open an XML file in .NET and it has a username & password. So piece of cake, you just use XmlUrlResolver.Credentials except... that only works if it's an http or ftp url that requires a username & password.

But what if it's a share on a network drive that requires a username & password to access the file? That gets complicated. Is your app running on a workgroup login or a domain login? Is the file one a workgroup or domain? Is it the same domain? Are the required credentials a user on that machine or a domain user? Or are the permissions a domain group which requires a domain user set of credentials?

Each of those combinations requires a different way of accessing the file. And a couple of combinations are impossible to access, even though "net use" can do it. This is definitely a place where I think Microsoft decided it was too hard to do and so gave up.

And if you find ways to implement some of the remaining (very rare) combinations, please post a comment.

Download XmlFileOpen.cs

Get all types a COM object implements

When you get a COM object in C#, if you know classes & what interfaces it implements, you can easily cast it to the desired type. But what about when you don't know it's type. Or more to the point, you think you know it's type and it doesn't implement that type. What to do.

The following method will return all Types that a COM object implements. I don't use this in production code but I do use it occasionally when writing code.

Download SystemUtils (the below code)  

/// <summary>
/// Get all implemented types in a COM object. Code based on work at
/// http://fernandof.wordpress.com/2008/02/05/how-to-check-the-type-of-a-com-object-system__comobject-with-visual-c-net/
/// </summary>
/// <param name="comObject">The object we want all types of.</param>
/// <param name="assType">Any type in the COM assembly.</param>
/// <returns>All implemented classes/interfaces.</returns>
public static Type[] GetAllTypes(object comObject, Type assType)
{
    // get the com object and fetch its IUnknown
    IntPtr iunkwn = Marshal.GetIUnknownForObject(comObject);

    // enum all the types defined in the interop assembly
    Assembly interopAss = Assembly.GetAssembly(assType);
    Type[] excelTypes = interopAss.GetTypes();

    // find all types it implements
    ArrayList implTypes = new ArrayList();
    foreach (Type currType in excelTypes)
    {
        // com interop type must be an interface with valid iid
        Guid iid = currType.GUID;
        if (!currType.IsInterface || iid == Guid.Empty)
            continue;

        // query supportability of current interface on object
        IntPtr ipointer;
        Marshal.QueryInterface(iunkwn, ref iid, out ipointer);

        if (ipointer != IntPtr.Zero)
            implTypes.Add(currType);
    }

    // no implemented type found
    return (Type[])implTypes.ToArray(typeof(Type

 

Great Windows programming resource

The Microsoft support team in China has started a really good code snippet site at http://www.codeplex.com/helloworld Just 3 examples so far but if they run with it this may become step 1 for finding out how to do something in Windows.

Named Pipes in .NET

Like apparently 1 million other developers (according to Google) I needed to set up a named pipe in .Net. The problem is that what I found was either overkill or buggy. So I started with the code at Paranoid Ferret, fixed the bugs I found (you need to open the streams before returning from the connect method), and added a Dispose() to both sides.

This code (NamedPipes.zip) is designed to be a very simple system where a server and multiple clients can send text messages to each other asynchronously. And note that the messages come in on the pipe's threads so you need to Invoke to the UI thread if you are going to touch any of the UI.

This code could use improvement.

  1. I tried running it in message mode but the call on the client side to put it in message mode failed. If anyone can tell me why or can fix it, please let me know.
  2. The blocking reads on both sides should use events so that the thread can be killed by triggering the event. And the OVERLAPPED struct should be created with an event on the server side for this same purpose. I did not do this because I don't know the SDK events real well and I saw conflicting recommendations about how to use them here. Again, if you know the correct way to do this, please let me know.

This code has been thoroughly tested here and is 100% solid, at least in how we are using it.

Multiple UDP listeners on 1 computer

If you want to have multiple apps listen for the same UDP broadcast on a single computer, setting it up in .NET is a couple of extra lines of code. If you don't do this, it will only let the first app bind to this port/address.

Two key issues here:

  1. Set the option to ReuseAddress
  2. Bind to IPAddress.Any

string stringGroupAddress = "224.168.101.200";
IPAddress groupAddress = IPAddress.Parse(stringGroupAddress);
int groupPort = 1707;

UdpClient groupSocket = new UdpClient();
groupSocket.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
groupSocket.Client.Bind(new IPEndPoint(IPAddress.Any, groupPort));
groupSocket.JoinMulticastGroup(groupAddress);

indent positioning in DOCX

Many thanks to Jialiang Ge at Microsoft for this.

  • First, to get the final state of any property (including indents), we need to follow the style hierarchy rules in §2.7.2 of the specification
    • There, it correctly states that the direct formatting (the pPr under the p element) supersedes the version in the list definition
    • Since tab stops are additive, we just gather them all up and we have the full set of tab stops
  • Now, we display the list as follows:
    • First, check the numFmt element §2.9.18 to see the format of any numbers in the list definition.
    • Next, place the text in the lvlText element §2.9.12 at the location of the final left indent.
      • If the numFmt isn’t “bullet”, we need to replace the %[1-9] syntax appropriately.
    • Now, look at the suff element §2.9.30 to see what separates the bullet from the text.
      • If it’s space or nothing, add a space or nothing.
      • If it’s tab, add a tab. (Note: this is the default if suff is not set!)
        • Then we just need to know what the next tab stop is.
        • For that, any tab stop after the end of the displayed level text is valid:
          • Tabs set with the tab element
          • Any hanging indent (as long as the doNotUseIndentAsNumberingTabStop element §2.15.3.2 is not set)
          • Default tab stops at the distances set by the defaultTabStop element §2.15.1.24
  • Finally, we justify the result – from start of the level text to end of the line. You justify now so that it’s always relative to the same tab stops.

One more thing - the use hanging tab only occurs in Word 2007 - and it's the default in 2007 which makes it sort of weird:

  • For Word xml file, the default behavior of Word 2003 and 2007 is to omit the virtual hanging tab (If Word 2007, we have an option to make Word enable the hanging tab)
  • For normal Word 2003 doc files opened in Word 2003, the virtual hanging tab is always omitted.
  • For normal Word 2003 doc files opened in Word 2007, Word 2007 will automatically set the option “Don’t use hanging indent as tab stop for bullets and numbering” selected, and omit the hanging indention.
  • For normal Word 2007 docx files opened in Word 2007, Word 2007 will use hanging indent as tab top for bullets and numbering by default.
  • For normal Word 2007 docx files opened in Word 2003, Word 2003 will omit the virtual hanging tab, and therefore, may misaligned the document. (see KB http://support.microsoft.com/kb/937936)

But there is another caveat on the virtual hanging indent - in RTF/DOC/WordML the virtual hanging indent tab stop is used - if and only if - there are no tab stops set in the list, paragraph, or styles (list/paragraph style) after the virtual position.

And one more... If there is a <w:tab val='clear'.../> then that tab is cleared and not only does not count as a tab, but clears out any parent tabs (style, list) that are at the same position.