June 2005 - Posts

Tabbed Browsing in Visual Studio

Don Box points out the neat tabbed browsing support in Visual Studio 2005. It’s certainly way better than the tabbed browsing provided by the MSN Toolbar which flickers terribly as it switches IE windows.

Another tip is to use the VS 2005 Document Explorer (used by the MSDN Library) which uses the same IDE for tabbed browsing and you get to store links in the Help Favorites.

The main drawback is that it doesn’t include any of the popup blocking provided by Internet Explorer so make sure you don’t visit cnn.com …


© 2005 Kenny Kerr

Posted by KennyKerr with 3 comment(s)

OneNote PowerToy Contest

Does anyone know whether Visual Studio 2005 Beta 2 can be used to develop power toys for the contest? The official rules simply state:

“Programming language must be C++, C# or VB.NET”

I would hate for a bunch of programmers to spend the time building power toys only to be disqualified because they didn't use Visual Studio 2003. As Brian put it (in a messenger conversation), this seems like a great cross-product promotional event.

Come on OneNote team, how about it?


© 2005 Kenny Kerr

Posted by KennyKerr with 5 comment(s)

WTL 7.5 on SourceForge

A new version of the Windows Template Library (WTL) was released earlier this month and includes support for Visual Studio 2005 Beta 2. This is a great library for building native Windows applications.

http://sourceforge.net/projects/wtl/


© 2005 Kenny Kerr

Posted by KennyKerr with no comments
Filed under:

Broken Links

My web hosting provider (http://www.serverintellect.com/) seems to be out of service at the moment so downloads and images on my blog aren’t available as they’re hosted on my site (http://www.kennyandkarin.com/). It will hopefully be restored in the next few hours.

Update: we’re back online. It seems half the sites I visited were down. ServerIntellect by the way is the best hosting service I’ve encountered.


© 2005 Kenny Kerr

Posted by KennyKerr with no comments

Is P/Invoke Dead?

A reader recently asked whether P/Invoke is dead since you can use C++ Interop and avoid re-declaring all the functions and structures that you might already have in system header files.

Firstly, P/Invoke is still extremely useful for languages like C# that can’t consume header files, but then that should be obvious. Secondly, P/Invoke can also be useful for calling functions for which you don’t readily have header and lib files for and avoids resorting to calling LoadLibrary followed by GetProcAddress.

What may not be as obvious is that P/Invoke can still be very useful from C++ for other reasons. Although you can avoid P/Invoke entirely in your C++ projects there are times when the code can actually be simpler if you just use P/Invoke instead. Let’s look at a few examples.

Lets say you’re mixing native (HWND) and managed (Windows.Forms.Control and derived classes) windows in a project. You might be using the Form class as the main window for your application and HWNDs (window handles) to represent windows in another process. So the challenge is to get the window text from an HWND and display it in a Windows.Forms control. Essentially the problem boils down to implementing the following function:

String^ GetWindowText(HWND windowHandle);

Given a window handle, we would like to get the window text as a managed string. As a C++ programmer you might naturally write the following implementation:

String^ GetWindowText(HWND windowHandle)
{
    String^ result = String::Empty;
    int textLength = ::GetWindowTextLength(windowHandle);
 
    if (0 < textLength)
    {
        std::vector<wchar_t> buffer(textLength + 1);
 
        if (0 == ::GetWindowText(windowHandle,
                                 &buffer[0],
                                 textLength + 1))
        {
            throw gcnew ComponentModel::Win32Exception(::GetLastError(),
                                                       "The GetWindowText User32 function failed.");
        }
 
        result = Runtime::InteropServices::Marshal::PtrToStringUni(IntPtr(&buffer[0]));
    }
 
    return result;
}

We start by getting the text length with a call to the GetWindowTextLength function. If the window has any text, we use the indispensable vector class to manage the buffer that the GetWindowText function will use to write the text to. 1 is added to the length of the buffer as the GetWindowText function null-terminates the text written to the buffer. If you neglect this step the text will be truncated. Finally, the PtrToStringUni helper method from the Marshal class is used to convert the null-terminated string into a managed string.

Another solution is to use the marshalling services provided by the CLR for P/Invoke to avoid the native string management and conversion. Consider the following solution:

using namespace Runtime::InteropServices;
 
[DllImport("User32.dll", CharSet=CharSet::Unicode, SetLastError=true)]
int GetWindowText(HWND windowHandle,
                  Text::StringBuilder% text,
                  int count);
 
String^ GetWindowText(HWND windowHandle)
{
    String^ result = String::Empty;
    int textLength = ::GetWindowTextLength(windowHandle);
 
    if (0 < textLength)
    {
        Text::StringBuilder buffer(textLength + 1);
 
        if (0 == GetWindowText(windowHandle,
                               buffer,
                               buffer.Capacity))
        {
            throw gcnew ComponentModel::Win32Exception(::GetLastError(),
                                                       "The GetWindowText User32 function failed.");
        }
 
        result = buffer.ToString();
    }
 
    return result;
}

Here we use the DllImport attribute to indicate to the CLR that the GetWindowText function is implemented by the User32 DLL. The function is prototyped with the .NET Framework’s StringBuilder class to represent the text buffer and a tracking reference is used so we can use stack semantics for the StringBuilder object when calling the function. As you can see, the GetWindowText implementation is very similar to the original. We still use the GetWindowTextLength directly as there is no benefit in using P/Invoke for it. Of course the solution using P/Invoke is 7 lines longer than the first solution and requires that you translate the GetWindowText function into a P/Invoke declaration for the CLR. About the only thing good about this solution is that you’re not using native memory which could become a performance problem in some rare cases. Of course you’d want to profile this to actually make such a conclusion.

Here’s a more compelling example. For a project I was working on a few months back I needed to allow the user to pick computers from the network. I decided to use the Active Directory Object Picker dialog box. If you’ve never had the pleasure of using this little gem, its exposed through the IDsObjectPicker COM interface and can be a challenge to get just right even from C++. Needless to say using P/Invoke from C# would just be nightmare. To make life simpler I wrapped the functionally we needed in a DLL written in native C++ and exposed it with the following function:

HRESULT __stdcall BrowseForComputers(HWND parentWindow,
                                     bool multiSelect,
                                     SAFEARRAY** computers,
                                     bool* dialogResult);

I’ll spare you the details of its implementation. For this function it would be very useful to be able to use P/Invoke since there is quite a bit of overhead involved in calling this function. Firstly we need to deal with COM safe arrays which are really not fun to work with. Secondly we need to check the HRESULT error code for failure. And finally we need to check the dialogResult pointer (if you remember MIDL then just think [out,retval]) to check whether the user pressed OK or Cancel. This is where P/Invoke and managed code really makes me smile. Consider the following example of using this function:

[DllImport("Native.dll", PreserveSig=false, CharSet=CharSet::Unicode)]
bool BrowseForComputers(IntPtr parentWindow,
                        bool multiSelect,
                        [MarshalAs(UnmanagedType::SafeArray, SafeArraySubType=VarEnum::VT_VARIANT)]
                        array<String^>^% computers);
 
void main()
{
    array<String^>^ computers = nullptr;
 
    if (BrowseForComputers(IntPtr::Zero, // parent
                           true, // multi-select
                           computers))
    {
        for each (String^ computer in computers)
        {
            Console::WriteLine(computer);
        }
    }
}

Although the declaration of the BrowseForComputers function can take a few moments to get just right, using it is very simple and elegant. The CLR takes care of all the marshalling and error translation.


© 2005 Kenny Kerr

Posted by KennyKerr with 4 comment(s)
Filed under: ,

Special Folders Browser

When using the Environment.SpecialFolder enumeration I often spend a few extra moments checking what path a particular SpecialFolder constant refers to on my computer. Since it can be different from machine to machine and user to user it can help to quickly identify where the special folders point to. I got tired of writing the same boilerplate code over and over again so I quickly wrote the Special Folders Browser.

Some useful features:

  • Clearly displays the current path that each special folder represents.
  • “Open in Explorer” button to jump to the specified path in Windows Explorer.
  • “Copy C++/C# Code” buttons which copy the necessary code to the clipboard to save you some typing.

Here are some handy shortcuts:

  • Double click to open folder in Windows Explorer
  • Alt+E for “Open in Explorer”
  • Alt+C for “Copy C++ Code”
  • Alt+O for “Copy C# Code”

This tool was compiled for the .NET Framework 2.0 Beta 2. Oh, and it uses reflection so the enumeration constants are not hardcoded just in case the list changes between now and the RTM.

Download it here. In an upcoming post I'll be talking about language choice and why I wrote this tool in C#!


 © 2005 Kenny Kerr

Posted by KennyKerr with 2 comment(s)
Filed under: , , ,

Independent Microsoft Technical Evangelist?

Hi, my name is Kenny Kerr and I am an Independent Microsoft Technical Evangelist.

Unlike Jeff I don’t actually work for Microsoft. I do however love technology, in particular Microsoft technology, and promote it in various ways including through my community involvement, answering questions on developer forums, writing articles for MSDN, articles on this blog, and in an upcoming book that I am writing for Addison Wesley on Visual C++. I am probably most well known (I’m just guessing here) for my writings on Visual C++, in particular my article introducing C++/CLI. I have however started noticing that a number of folks in the industry naturally assume that I actually work for Microsoft. This may be compounded by the fact that Microsoft even seems to think that I work for Microsoft.

Anyway, this is not the case and I thought I should clear that up.

I actually interviewed for a PM position on the Visual C++ team a few years back (has it been that long?!) that went really well but there was some complication with H1B visas (I live in British Columbia). Perhaps I should give Gretchen a call.

:)

I actually made up the term “Independent Microsoft Technical Evangelist” as a joke while introducing myself in a meeting I had with some of the PMs and architects on the Microsoft Virtual Server team a while back as part of my day job…


© 2005 Kenny Kerr

Posted by KennyKerr with 1 comment(s)

Lesson of the Day

Don’t mess with nerds.

Go Rory!

 

[Update: cleaned it up a little for my younger readers]

:)


© 2005 Kenny Kerr

Posted by KennyKerr with no comments

Humans and Mac Minis

This is hilarious and yet so sad.

I’m sorry Eric. I know how you feel. Some days it really sucks to share the planet with other humans. They can be so devoid of honor.

But the show must go on…


© 2005 Kenny Kerr

Posted by KennyKerr with no comments

Initializing Arrays and Aggregates

Jordy posted a question to MSDN’s new forums website that I thought would be interesting to readers of my blog. Basically he wants to convert the following native C++ code to managed code:

class Constant
{
public:
    String Name;
    double Value;
};
 
static const Constant ConstTable[] =
{
    { "e", 2.718281828 },
    { "Pi", 3.14159265358979323846 },
    { "c", 299792458.0 }
};

There are a few aspects to this code that are worth noting as we look for a managed alternative:

  • The ConstTable declaration includes the static keyword which indicates that the array has static duration. It is also a global variable and as such will have internal linkage. Briefly this means that different instances of the ConstTable identifier will refer to the same identifier but only within the translation unit.
  • The Constant class is an aggregate and can be initialized with a comma-separated list of values in curly braces. Aggregate types don’t have constructors, non-public member variables, base classes or virtual functions.

Here is a simple solution using managed code:

value class Constant
{
public:
    String^ Name;
    double Value;
};
 
ref struct StaticClass abstract sealed
{
    static initonly array<const Constant>^ ConstTable =
    {
        { "e", 2.718281828 },
        { "Pi", 3.14159265358979323846 },
        { "c", 299792458.0 }
    };
};

A few things are worth noting: A value class is used for defining Constant since ref classes don’t qualify as aggregate types. Value classes are also more efficiently stored and accessed in memory and are stored continuously in the managed array. An abstract sealed class is used to house the static array since managed types cannot be global variables.

The storage and linkage options offered by native C++ are useful but can get tricky as applications are built from different libraries. The CLR provides a conceptually simpler model for defining types and variables even if not all of the flexibility of C++ is available to managed types.


© 2005 Kenny Kerr

Posted by KennyKerr with 1 comment(s)
Filed under: ,
More Posts