Tuesday, January 31, 2006

Visual Studio 2005 Intellisense seems unreliable...

I've now been working with Visual Studio C++ 2005 for a couple of weeks and I am beginning to get to know it better... and get to know its quirks. Intellisense seems buggy! Again! Overall it is surprisingly good ... as long as it works. But every now and then, usually every 5 minutes or so, it seems to stop working alltogether. And especially when I need it most such as after I have added a new method to a class.

I found out that in fact, most of the times it is still working, but it just takes more time to update itself than I'd expect. Here is a tip that helps me keep Intellisense running:

Immediately above the text editor window there are two comboboxes. The left one shows the scopes of the current file and the right one shows the list of methods of the scope. They are called the 'navigation bar'. This has been in Visual Studio for a long time and is very useful to navigate through the classes.

It is a very useful indicator for Intellisense as well. The problem with Intellisense is not so much that it stops working alltogether, but that it is a lot slower than I type.

When a definition changes, Intellisense updates itself in the background, but only during idle time. I am a fast typer. I add a declaration and then switch to the .cpp file to write the definition, typing away continuously. This prevents Intellisense from updating itself, since it is waiting for a small pause in my typing which never comes. How small? This is where the comboboxes of the navigation bar come in handy.

Try this: add a method to one of your classes in your header file, say void my_class::show_something(); Now switch to the end of the corresponding cpp file and type void my_class::show_something() { sometext.... . Do so without a pause. Watch the right combobox. Initially it is empty. About one second after you stopped typing it should change to show_something. This indicates that Intellisense finally caught up and will work inside show_something again. But if you continue typing without a pause, the combo box stays empty or takes a lot longer to fill. This gives the impression that Intellisense does not work, especially when I need it most: when I write new code.

After you've changed or added a definition, stop typing while inside a method and wait until the upper right combobox shows the name of the method again.

Use the upper right combobox as an indicator for Intellisense.

Also I find that Intellisense is extremely sensible to temporary code changes. Consider this:

void my_method()
if (something) {

This happens all the time while you are changing code. When you introduce a new compound statement and type the opening bracket {, for a short time the code is invalid. The closing bracket is missing. This sort of code changes can confuse Intellisense. It has difficulties parsing the code. Since it is rather slow on updating it may take another second after you've added the closing brace } until it is working again.

If you want to know more about this, open the task manager and have an eye on the CPU usage. Experiment a little, get to know Intellisense, adapt your speed and see Intellisense improve.

So usually, when hitting Ctrl+Space does not expand the name rightaway, I pause of for a second and try again.

Note: It is important to close the Intellisense member list combobox if it is open. Intellisense does not update itself while it is open.

Something else I found: Editing a source file in another editor such as DialogBlocks also seems to confuse Intellisense. I haven't yet found out why. Sometimes the entire class definition stops working, somethings it seems unaffected. I'll keep you updated if I find something. If you've got an idea, please leave a comment.

Monday, January 02, 2006

wxWidgets, VC++8.0 and XP theme look and feel

I an previous post I talked about setting wxUSE_NO_MANIFEST=0 to avoid linker errors when you compile your wxWidgets application with Visual Studio 8.0. Turns out this was only half the story.

Your application looses Windows XP themes for all controls.

Add these lines to your precompiled header file "stdwx.h" if you have one, or to one of your .cpp files, preferably the applications .cpp file. (Please unwrap these lines. Every line should start with the preprocessor symbol '#'):
#if _MSC_VER>=1400
#if defined _M_IX86
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"")
#elif defined _M_IA64
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='' processorArchitecture='ia64' publicKeyToken='6595b64144ccf1df' language='*'\"")
#elif defined _M_X64
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"")
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")

Background: With Windows XP, your application must include a 'manifest' in its binary. This manifest tells Windows XP what version of what DLL your application uses. Among other things this enables 'Side By Side' installation, where two applications load a DLL of the same name, but with different versions.
Beginning with Visual Studio 8.0, the CRT runtime library DLLs are no longer found in the $PATH environment variable. Instead the linker generates a manifest for each application created with VS 8 and writes the requested DLL version into the binary. You must define wxUSE_NO_MANIFEST=0 for the .rc file to tell the resource compiler to ignore the standard wx manifest file. Otherwise the linker will give an error, since it then would see two manifests, the wx manifest and the one it generates itself.
But the manifest file generated by the linker does not include the neccessary information for the common controls version 6.0, which is responsible for the Windows XP themes for controls such as buttons. So by default, the application will have the XP themed frame with the blue bar and the bright red 'X' button in the upper right corner, but will still have the old Win2K style buttons inside the frame.
The reference to the common controls version 6.0 was contained in the wx manifest, which is no longer used due to wxUSE_NO_MANIFEST.
The lines above tell the linker to add the common controls version 6.0 to the manifest and your application will get the XP theme look back for its controls.