Programming magic, glory, and juices.

ListView_GetHeader returning NULL

September 1st, 2009


I ran into a problem with ListView_GetHeader returning NULL for a ListView that had a header during WM_INITDIALOG. The issue ended up being that if the ListView was initially created hidden, I wasn’t able to get the header window. However, when the ListView control was created with WS_VISIBLE, it returned the header as expected. What I think happens is that the ListView control in Windows doesn’t actually create the header window until the first time it becomes visible, that’s why calls to ListView_GetHeader returned NULL when I thought they shouldn’t have.

So during WM_INITDIALOG, before the dialog is shown, I set each ListView to visible and then back to whatever state it was before. That way it forces the ListView to create the header window internally.

Style = GetWindowLong(ListViewWnd, GWL_STYLE);
ShowWindow(ListViewWnd, SH_SHOW);
if ((Style & WS_VISIBLE) == 0)
    ShowWindow(ListViewWnd, SW_HIDE);
HeaderWnd = ListView_GetHeader(ListViewWnd);

Targeting Windows 95 in Visual Studio 2008

August 23rd, 2009


If setting up a Virtual PC image with Windows 95 on it isn’t difficult enough, I had the audacity to try and run a application built using Visual Studio 2008 on Windows 95.

To those who are trying to install Windows 95 on Virtual PC 2007, it appears the Windows 95 is no longer supported on Virtual PC. What I had to do is install DOS on the image, copy all the Windows 95 setup files onto the virtual hard disk image (via mounting it in Windows 7), and then running the setup. It won’t work if you try and mount the Windows 95 ISO in Virtual PC because the CD-ROM isn’t recognized when Windows 95 setup restarts.

Virtual PC Guy’s WebLog: Installing Windows 95 under Virtual PC

Virtual PC still has its problems with Windows 95, sometimes it will come up and say “While initializing device IOS: Windows protection error. You need to restart your computer.” That happens if you have hardware virtualization turned on.

Thread: Win 95 install problem, in Virtual PC

I was disappointed to see that Microsoft removed Windows 95 from MSDN. There also isn’t 98/ME/NT4. It has to do with Microsoft settling a lawsuit with Symantec. Suprisingly even Visual C++ 6.0 isn’t on MSDN, but I don’t know if that is for the same reason or not. I had to grab Windows 95 from Mininova.

To get an application to run in Windows 95 you have to make sure that it doesn’t link to any functions that are not available to Windows 95. You can do this by setting the _WIN32_WINNT preprocessor definition variable to 0×0400 (/D “_WIN32_WINNT=0×0400″). That should expose which functions and structures are not available in Windows 95.

If the application you are using uses Unicode function calls you have to implement the Microsoft Layer for Unicode on Windows 95/98/ME Systems. Unicode wasn’t a part of Windows until Windows NT. I had to link with unicows.lib and set unicows.dll as a delay loaded dll in order for it to work.

If that wasn’t difficult enough, whenever you compile your application in Visual Studio 2008 it modifies the PE’s NT Optional Header and sets the MajorSubsystemVersion and MinorSubsystemVersion. These two properties tell Windows whether or not it will be able to support the application. So if Visual Studio 2008, sets it to 0×0500, then when you try and launch the application in Windows 95 (which is 0×0400), it will throw an error that says, “File expects a newer version of Windows – Upgrade your Windows”. To get around this, I found an AWESOME product called LegacyExtender, which includes a utility EditVersion.exe, that modifies the PE’s SubsystemVersion properties. You can setup a post-build operation to call “EditVersion.exe $(TargetPath) 4.0″. LegacyExtender also includes a .lib which links in function wrappers for the most common functions that Windows 95 doesn’t have (IsDebuggerPresent, InitializeCriticalSectionAndSpinCount, etc).

LegacyExtender
PE Disassembly Viewer – NikPEViewer
MSFN Thread: Visual Studio 2008 and Windows 9x

Targeting Windows 95 was a lot of fun, just to see if I could do it. It wasn’t an easy journey. It really makes you search out the bare bone functions that will work in Windows to get a particular job done.

Shell Context Menus and Custom Buttons

August 22nd, 2009


It is not easy to get icons working on shell context menus. Each version of Windows has its own way of putting icons on context menus. I came across this great article about the proper way of setting an icon on a shell context menu.

nanoant: Themed menu’s icons, a complete Vista and XP solution (updated)

The code is based off TortoiseSVN’s context menu. The only problem with it is the fact that it causes Windows to display two icon columns on the menu in the Classic theme. This occurs because legacy context menu extensions will use the MENUITEMINFO’s hbmpChecked and hbmpUnchecked properties to set the bitmap icon. TortoiseSVN uses the hbmpItem property which is a newer way of setting the bitmap. The way to get around having to icons is to set the style of the menu via SetMenuInfo so that the menu has the MNS_CHECKORBMP style flag set. The Aero theme actually sets this style on all menus automatically which is why the issue can’t be seen in Aero.

Below is are screenshots of the context menu with two icon columns (left) and one icon column (right).



Two icon columns

One icon column

I submitted a patch to TortoiseSVN to fix it today.

One issue I came across while superclassing a button in Windows has to do with the fact that when the button processes the BM_SETSTATE message it does internal painting without calling WM_PAINT. This caused problems for me because I was doing custom painting and in certain cases, the button would paint its default look. I tried just returning true during the BM_SETSTATE message, instead of letting it go to the original procedure, but that caused the button clicks not to work. So I found this Dr. Dobbs article that shows that you have to set some flags (BST_PUSHED, ..) in the window’s extra memory.

Dr. Dobbs – Writing Windows Custom Controls

Update 9/5/2009:
The issue with BM_SETSTATE doing internal drawing without calling WM_PAINT is only present in older versions of the commons control library. If you attempt to set the button window’s extra memory values like that with a newer version of the common controls library, then it will crash your application. So if it does crash, check to see that you aren’t including a manifest which specifies a higher version of the common controls library.

Windows API: A SET without a GET?!!

June 9th, 2008


How is it possible that Microsoft didn’t introduce PBM_GETBKCOLOR/PBM_GETBARCOLOR until Windows Vista? I mean, I can’t imagine it! The progress bar messages PBM_SETBKCOLOR and PBM_SETBARCOLOR are supported in Windows 95+, but it took them until Vista to develop PBM_GETBKCOLOR and PBM_GETBARCOLOR??!! How do failures like that go overlooked for such a long period of time? Sounds like they have some lazy developers are Microsoft.

ResHacker 256×256 Icon Bug

April 8th, 2008


Was working on my utility today that injects an icon into an executable and found out that ResHacker does not support icons that are 256×256 pixels. It is actually a bug, because in the ICONDIRENTRY structure, which defines an icon in an icon group, the Width and Height properties are defined as BYTE’s. Well a BYTE cannot hold the value 256. So, instead the common practice has been to use 0 to indicate the value of 256. When ResHacker sees the value of Width and Height as 0 it thinks it has run out of memory and so throws a “Out of system resources” error message.

Anolis has got to be the best resource editor I’ve found.
I wrote the author of the program, but the website says ResHacker it is no longer under development and that I should use XN Resource Editor. Too bad it doesn’t support drag and drop thou.

Wikipedia Icon File Format

Supporting Unicode

January 6th, 2008


Windows’ Unicode Support
All internal functions in Windows use the Unicode format UTF16 natively. The book Windows Internals mentions that when a developer calls an the ANSI version of a function that Windows converts all the function’s parameters that are ANSI strings to Unicode and calls the Unicode version of the function. Then when the Unicode function is finished, Windows will then convert the Unicode result strings back to ANSI and return. ReactOS which is modeled off Windows allocates a new string buffer for each conversion that needs to take place.

String Library
Such string conversion layers work well for a higher level API, but for core API or for a string library it would not do. It would be insane to have to do a ANSI to Unicode conversion for each string function needing to be called. You would have to allocate a new string buffer each time you wanted to call a string function.

When ends up happening with string libraries is that a lot of duplicate code ends up being created. For each string function multiple encoding format functions have to be written. And this is done so that 1). you don’t encur the overhead cost of conversion and 2). for side-by-side encoding support. Having side-by-side encoding support is important because you’ll find you end up needing to use encoding formats other than the default encoding format that you are building your project in.

Side-by-side support for ANSI/ASCII and Unicode/UTF16

#ifdef UNICODE
#define String_Copy   StringUtf16_Copy
#else
#define String_Copy   StringAscii_Copy
#endif

int32 StringUtf16_Copy(wchar *Target, wchar *Source);
int32 StringAscii_Copy(char *Target, char *Source);

In the code example above, you can call String_Copy to copy a string based on the build encoding for your project or if you need to explictly call the UTF16 or ASCII versions of String_Copy throughout your code you can do that as well.

Windows API macros are set up the exact same way, the only difference is that the ANSI functions call Unicode functions, something which is not reasonable to do with a string library due to the conversion overhead.

TCHAR
Most functions won’t need side-by-side support in that you’ll need both an ANSI version and a Unicode version. For these functions we can use TCHAR which is defined as the char type for the current project’s build encoding.

#ifdef UNICODE
#define tchar   wchar
#else
#define tchar   char
#endif

int32 File_Open(int32 FileHandle, tchar *Filename, int32 Flags);

Naming
Naming conventions are always important. The cleaner you name your functions and variables the better. Windows names the ANSI version of a function by appending an ‘A’ and a Unicode version of a function by appending a ‘W’ for wide char. For instance in Windows their is a LoadImageA and LoadImageW and the LoadImage macro selects which function to call based on the character encoding for your project. If I were to do the same thing I would have ended up with String_CopyA and String_CopyW. Or I could do it the exact opposite and name it how the C runtime library does and prepend a ‘w’ only on Unicode functions in which case I would end up with String_Copy and WString_Copy. Too me neither really look right. So because the character encoding type is not recongizable in the letters ‘A’ and ‘W’ I decided to use the name of the format appended to the end of the class name. What would I do if I had to add another character encoding to the string library? Add an ‘X’? Functions that use multiple character encodings will have variable names in the format Filename for ASCII, Filename8 for UTF8, and Filename16 for UTF16.

Happy Coding. The End.

Delete IE Cache the Right Way

November 3rd, 2006


There are some really awful examples out there on how to delete the cache in Internet Explorer using the Windows API. The method is simple, but the implementation is difficult.

To be able to delete all the cache entries you must first iterate through them. You can do this using FindFirstUrlCacheEntry and FindNextUrlCacheEntry. These two functions are possibly the worst iteration functions to come out of Microsoft.

Deleting each cache entry during each iterating can lead to problems, mainly the possibility that not all the cache entries will be deleted. I believe I read a newsgroup posting that said FindFirstUrlCacheEntry and FindNextUrlCacheEntry get confused when using DeleteUrlCacheEntry during each iteration. I’ve found that doing so will only remove about 10% of the total cache entries.

Let me explain FindFirstUrlCacheEntry and its brother function a moment. They both require a variable length buffer to be able to store information about the next cache entry during iteration. Furthermore you can get the length of the required buffer by either passing the function an allocation with not enough memory or by not passing the function anything. Each time you call either FindFirstUrlCacheEntry or FindNextUrlCacheEntry you must pass in a pointer to a integer that specifies the size of the buffer that you are also passing in. Failure to set this size parameter’s value before calling these functions will result in further problems.

So here is the plan. First iterate through each cache entry using FindFirstUrlCacheEntry and FindNextUrlCacheEntry. While iterating create a new memory buffer that houses that particular cache entry’s information. When we are done iterating through all cache entries we delete them one by one using DeleteUrlCacheEntry. After all cache entries have been deleted we free the remaining memory that stores each cache entries information.

Not all the required code is represented here.

uint32 Size = 0;
HANDLE Handle;
LPINTERNET_CACHE_ENTRY_INFO Info;

/* Get the size of the first cache entry */

FindFirstUrlCacheEntry(NULL, NULL, &Size);

// TODO: Allocate new buffer "Info" with the length of "Size"
// TODO: Add buffer "Info" to linked list for later deletion

Handle = FindFirstUrlCacheEntry(NULL, Info, &Size);

while ((Handle != NULL) && (GetLastError() != ERROR_NO_MORE_ITEMS))
    {
    /* Zero out "Size" so we can check for next entry's required buffer size */

    Size = 0;

    /* Get next entry's buffer size */

    FindNextUrlCacheEntry(Handle, NULL, &Size);

    if (Size == 0)
        break;

    // TODO: Create new buffer "Info" with length of Size
    // TODO: Add "Info" to linked list for later deletion

    if (FindNextUrlCacheEntry(Handle, Info, &Size) == FALSE)
        break;
    }

FindCloseUrlCache(Handle);

This is the best way to iterate through Internet Explorer’s cache. First get the buffer size required to house each entry’s data then retrieve it. That way you don’t have to check for ERROR_INSUFFICIENT_BUFFER because you know you’ll always have the right sized buffer. Trying to have a single memory buffer that you continuously resize by is too messy. Actually deleting each cache entry is simple, just iterate through each item in your linked list called call DeleteUrlCacheEntry with the cache data that you have stored. When everything has been deleted then free each item in your linked list. Didn’t I say it was easy as a piece of crumb cake?