« Posts tagged windows

WinBioEnrollCommit Hang

Recently I have been working with the Windows Biometric Framework (WBF) for some fingerprint scanner applications. One of the methods in the API is WinBioEnrollCommit.

I have been using the async calls of the API exclusively, and naturally I was calling the function WinBioEnrollCommit within the callback that was passed to WinBioEnrollCaptureWithCallback. This is slightly different from the only sample code that is provided with the MSDN documentation but I didn’t think twice about it as there is nothing mentioned about the requirements or threading characteristics of the framework and the callbacks.

So this lead to some very surprising application hangs or blocking in this call. It just would never return. However this could be related to the manufacturer implementation of the drivers.

Either way the solution was to move the WinBioEnrollCommit out of the callback function and into the same function that made the original call to WinBioEnrollCaptureWithCallback, while also making use of WinBioWait.

- On a another topic I have also found that none of the WBF API’s work correctly when run in an active x control when it is contained in the newer version of IE, 8 and above. There are some incompatibilities with the process architecture that s preventing any of the WBF calls from working correctly in that environment.

- Oh and WBF doesn’t really work over RDP.. strange

WPF WebBrowser script errors

The WPF WebBrowser control doesn’t expose all the features of the IWebBrowser2 interface. This can be a real pain, because the control doesn’t even expose the underlying activex interface to get around its short comings. Recently I needed to disable script errors from being reported. This can easily be done with the WinForms version of the control. I can across some simple reflection based code to get around the issue. This technique could be used to access other features of the IWebBrowser2 interface.

C#
<code>
public partial class Text : UserControl {
        public Text()
        {                               
            InitializeComponent();            
            browser.Navigated += new NavigatedEventHandler(browser_Navigated);
        }
 
        void browser_Navigated(object sender, NavigationEventArgs e)
        {
            HideScriptErrors(browser, true);
        }
 
 
        public void HideScriptErrors(WebBrowser wb, bool Hide)
        {
            FieldInfo fiComWebBrowser = typeof(WebBrowser).GetField("_axIWebBrowser2", BindingFlags.Instance | BindingFlags.NonPublic);
            if (fiComWebBrowser == null) 
                return;
 
            object objComWebBrowser = fiComWebBrowser.GetValue(wb);
 
            if (objComWebBrowser == null) 
                return;
 
            objComWebBrowser.GetType().InvokeMember( "Silent", BindingFlags.SetProperty, null, objComWebBrowser, new object[] { Hide });
 
        }
}
 
</code>

NSIS – KillProc doesn’t work with 64 bit processes

I am a fan of NSIS . I use it for most of my projects, its simple and quick to get up and running. (MSI is such a headache!) One of it’s problems is lack of a native 64 bit installer. This leads to some unexpected problems on 64 bit installations. I build a lot of shell extensions. Typically you want to restart explorer.exe once the installation has completed. There are a number of existing plugins for NSIS that provide this ability. But none of them will work on a 64 bit OS because explorer.exe is a 64 bit process and the installer is a 32 bit process.

So to get around this I have rewritten the commonly used KillProc plugin for NSIS, but internally it uses WMI. WMI uses a lot of COM objects to get the job done, and they do not suffer the same restrictions and re-directions that the standard 32 bit Win32 API calls experience.

Get a copy here, with source <download>

Just put the dll in your NSIS plugins directory and you should be able to use it just like the existing KillProc plugin.

All Code is freely provided, no guarantees or warranties about its quality, use at your own risk.

Merge two icons

The previous posts about ico formats and files have all been moving towards the end goal, merging two icons into a new single icon. This is useful for things like generating icon overlays and I personally used this method while building an icon overlay shell extension to combine multiple icon overlays into a single icon overlay. This is important because only windows only allows a single icon overlay extension to be “active” per file. So if you need to allow multiple overlays you need to merge the icons yourself and add additional logic to the shell extensions to get the correct result.

Here is a simple command line application that shows how to merge two icons. It takes three parameters,
expected usage:
icoMerge.exe [iconPath1] [iconPath2] [destinationPath]

Full source code is included. It is a combination of the source provided in the preivous ico related posts.
<download>

All Code is freely provided, no guarantees or warranties about its quality, use at your own risk.

ExtractIcon for larger Icons

Windows provides the function ExtractIconEx to extract icons from a exe or dll by index. It allows you to get a HICON handle to a “small” and a “large” version of the icon. Trouble is.. what are the actual dimensions of the small or large icons. The answer is to use GetSystemMetrics with the flags SM_CXICON, SM_CYICON, SM_CXSMICON, and SM_CYSMICON.

This is great, but unfortunately this function has not been updated for Vista or Windows 7, which use much larger icons and if you want a particular size ExtractIconEx will not work for you. So instead of relying on this function you can write some code that enumerates the resources in the target file yourself. The basic idea is to enumerate the resources and find the icons, then read the icon information to find the one that matches the desired size and format (bit count).

The example below implements this idea, it will find a 32bit icon of the requested size if it exists.

C++
<code>
 
HICON WINAPI ExtractIconAtSize(TCHAR* filePath, UINT nIconIndex, int sz)
{
  //Load the library as a data file
    HMODULE hLib = LoadLibraryEx(filePath, NULL, LOAD_LIBRARY_AS_DATAFILE);
    if( !hLib )
        return NULL;
 
    MyEnumData data;
    data.nIconIndex = nIconIndex;
    data.hIcon = NULL;
  data.sz = sz;
 
  //currently only interested in 32bit icons
  data.bitCount = 32;
 
  //find the resource item
    EnumResourceNames(hLib, RT_GROUP_ICON, (ENUMRESNAMEPROC)&FindGroupIconProc, (LONG)&data);
 
    FreeLibrary(hLib);
    return data.hIcon;
} 
 
typedef struct
{
  UINT      Width, Height, Colors; // Width, Height and bpp
  LPBYTE      lpBits;                // ptr to DIB bits
  DWORD      dwNumBytes;            // how many bytes?
  LPBITMAPINFO  lpbi;                  // ptr to header
  LPBYTE      lpXOR;                 // ptr to XOR image bits
  LPBYTE      lpAND;                 // ptr to AND image bits
} ICONIMAGE, *LPICONIMAGE;
 
#pragma pack( push )
#pragma pack( 2 )
typedef struct
{
   BYTE   bWidth;               // Width, in pixels, of the image
   BYTE   bHeight;              // Height, in pixels, of the image
   BYTE   bColorCount;          // Number of colors in image (0 if >=8bpp)
   BYTE   bReserved;            // Reserved
   WORD   wPlanes;              // Color Planes
   WORD   wBitCount;            // Bits per pixel
   DWORD   dwBytesInRes;         // how many bytes in this resource?
   WORD   nID;                  // the ID
} GRPICONDIRENTRY, *LPGRPICONDIRENTRY;
#pragma pack( pop )
 
#pragma pack( push )
#pragma pack( 2 )
typedef struct 
{
   WORD            idReserved;   // Reserved (must be 0)
   WORD            idType;       // Resource type (1 for icons)
   WORD            idCount;      // How many images?
   GRPICONDIRENTRY   idEntries[1]; // The entries for each image
} GRPICONDIR, *LPGRPICONDIR;
#pragma pack( pop )
 
struct MyEnumData
{
    UINT nIconIndex;
    HICON hIcon;
  int sz;
  int bitCount;
};
 
BOOL CALLBACK FindGroupIconProc(HANDLE hModule, LPCTSTR lpszType, LPTSTR lpszName, LONG lParam)
{
    MyEnumData *data = (MyEnumData*) lParam;
 
  //check if this is the index we want
    if( data->nIconIndex == 0 )
    {
        HRSRC hRsrc = FindResource((HMODULE)hModule, lpszName, lpszType);
        HGLOBAL hGroup = LoadResource((HMODULE)hModule, hRsrc);        
 
    GRPICONDIR * lpGrpIconDir = (LPGRPICONDIR)LockResource( hGroup ); 
        for( int i=0; i < lpGrpIconDir->idCount; ++i )
        {              
      //get icon header info
            GRPICONDIRENTRY * e = &lpGrpIconDir->idEntries[i];
            hRsrc = FindResource((HMODULE) hModule, MAKEINTRESOURCE( e->nID ), RT_ICON );
            HGLOBAL hGlobal = LoadResource( (HMODULE)hModule, hRsrc );
            ICONIMAGE *lpIconImage = (LPICONIMAGE)LockResource( hGlobal );
 
      //check the desired size and bit count
      if(e->bWidth == data->sz && e->wBitCount == data->bitCount)
      {
        data->hIcon = CreateIconFromResourceEx(
                        (PBYTE)lpIconImage,
                        e->dwBytesInRes,
                        TRUE,
                        0x00030000,//DWORD dwVersion,
                        e->bWidth,
                        e->bHeight,
                        0 );
        return FALSE;
      }
        };     
 
    return FALSE;
    }
 
    --(data->nIconIndex);
    return TRUE;
}
 
</code>

Read .ICO format.

Based on the last post below is a function for reading a .ICO file. The code only reads in the 32bit bitmaps in the icon skipping over the others. The function returns an array of HBITMAP’s of length bmpCount.

All Code is freely provided, no guarantees or warranties about its quality, use at your own risk.

C++
<code>
 
HBITMAP* ReadICO(TCHAR* srcPath, int* bmpCount)
{
 
  *bmpCount = 0;
 
  FILE* fp = _tfopen(srcPath,_T("rb"));
  if(fp == NULL)
    return false;
 
  ICONDIR icoDir;
 
  fread(&icoDir.idReserved,sizeof(WORD), 1, fp);
  fread(&icoDir.idType,sizeof(WORD), 1, fp);
  fread(&icoDir.idCount,sizeof(WORD), 1, fp);
 
  ICONDIRENTRY* entries = (ICONDIRENTRY*)malloc(sizeof(ICONDIRENTRY) * icoDir.idCount);
  memset(entries, 0, sizeof(ICONDIRENTRY) * icoDir.idCount);
 
  for(int i=0;i<icoDir.idCount;i++)
  {
    fread(&entries[i].bWidth,sizeof(BYTE), 1, fp);
    fread(&entries[i].bHeight,sizeof(BYTE), 1, fp);
    fread(&entries[i].bColorCount,sizeof(BYTE), 1, fp);
    fread(&entries[i].bReserved,sizeof(BYTE), 1, fp);
 
    fread(&entries[i].wPlanes,sizeof(WORD), 1, fp);
    fread(&entries[i].wBitCount,sizeof(WORD), 1, fp);
    fread(&entries[i].dwBytesInRes,sizeof(DWORD), 1, fp);
    fread(&entries[i].dwImageOffset,sizeof(DWORD), 1, fp);
 
  }
 
  HBITMAP* bmpResult = (HBITMAP*)malloc(sizeof(HBITMAP) * icoDir.idCount);
  memset(bmpResult, 0, sizeof(HBITMAP) * icoDir.idCount);
 
  HDC hdc = CreateCompatibleDC(NULL);
  for(int i=0;i<icoDir.idCount;i++)
  {
    if(entries[i].wBitCount != 32)
    {
      //only support 32bit
      continue;
    }
 
    fseek(fp, entries[i].dwImageOffset, SEEK_SET);
 
    ICONIMAGE ico;
    ico.lpBits = (LPBYTE)malloc(entries[i].dwBytesInRes);
    fread(ico.lpBits, 1, entries[i].dwBytesInRes, fp);
 
    ico.lpbi = (LPBITMAPINFO) ico.lpBits;    
 
    int height = ico.lpbi->bmiHeader.biHeight / 2;
    BITMAPINFO bmi;
    ::ZeroMemory(&bmi.bmiHeader, sizeof(BITMAPINFOHEADER));
    bmi.bmiHeader.biWidth = ico.lpbi->bmiHeader.biWidth;
    bmi.bmiHeader.biHeight = height;
    bmi.bmiHeader.biPlanes = 1;
    bmi.bmiHeader.biBitCount = ico.lpbi->bmiHeader.biBitCount;
    bmi.bmiHeader.biSizeImage = 0;
    bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bmi.bmiHeader.biClrUsed = 0;
    bmi.bmiHeader.biClrImportant = 0;
 
 
    HBITMAP hBitmap = ::CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, NULL, NULL, 0);
    if(((int)hBitmap) != ERROR_INVALID_PARAMETER && ((int)hBitmap) != ERROR_NOT_ENOUGH_MEMORY)
    {
      bmpResult[*bmpCount] = hBitmap;
      *bmpCount += 1;
 
      ::SelectObject(hdc, hBitmap);
      ::SetDIBitsToDevice(hdc, 0, 0, bmi.bmiHeader.biWidth, height,
                0, 0, 0, height, ico.lpBits + sizeof(BITMAPINFO), &bmi, DIB_RGB_COLORS);
    }
 
  }
  DeleteDC(hdc);
 
  fclose(fp);
 
  return bmpResult;
}
 
</code>

Convert HBITMAP to .ICO file

There is surprisingly little documentation or example code about the .ICO format. There are easy to use windows API functions to load icons from files and resources but only with limited options. Recently I have had to work with this format in detail and here I will give a code example of how to save a HBITMAP as an .ico file. I will only consider 32bit bitmaps\icons for now.

There is a detailed article on MSDN that gives a lot of background information, the only problem it was written in 1995, and has no information about how to deal with 32bit icons. But it still gives important details about the internal structure of the format and is worth looking at. http://msdn.microsoft.com/en-us/library/ms997538.aspx

The key difference with 32bit icons is the XOR map is not added to the entry. Also the color table is not 3 components(RGB) it is 4 components to include the 8bit alpha channel.

All Code is freely provided, no guarantees or warranties about its quality, use at your own risk. In my next post I will show how to read the .ico format.

 

First we need to define some structures, these are the same as those used in the MSDN article

C++
// These next two structs represent how the icon information is stored
// in an ICO file.
typedef struct
{
  BYTE  bWidth;               // Width of the image
  BYTE  bHeight;              // Height of the image (times 2)
  BYTE  bColorCount;          // Number of colors in image (0 if >=8bpp)
  BYTE  bReserved;            // Reserved
  WORD  wPlanes;              // Color Planes
  WORD  wBitCount;            // Bits per pixel
  DWORD  dwBytesInRes;         // how many bytes in this resource?
  DWORD  dwImageOffset;        // where in the file is this image
} ICONDIRENTRY, *LPICONDIRENTRY;
typedef struct 
{
  WORD      idReserved;   // Reserved
  WORD      idType;       // resource type (1 for icons)
  WORD      idCount;      // how many images?
  ICONDIRENTRY  idEntries[1]; // the entries for each image
} ICONDIR, *LPICONDIR;
 
typedef struct
{
  UINT      Width, Height, Colors; // Width, Height and bpp
  LPBYTE      lpBits;                // ptr to DIB bits
  DWORD      dwNumBytes;            // how many bytes?
  LPBITMAPINFO  lpbi;                  // ptr to header
  LPBYTE      lpXOR;                 // ptr to XOR image bits
  LPBYTE      lpAND;                 // ptr to AND image bits
} ICONIMAGE, *LPICONIMAGE;

Next we need a function that converts the HBITMAP into a ICONIMAGE structure, making sure the DIB is 32bit

C++
 
// How wide, in bytes, would this many bits be, DWORD aligned?
#define WIDTHBYTES(bits)      ((((bits) + 31)>>5)<<2)
 
ICONIMAGE CreateIconImageFromBitmap(HBITMAP bmp)
{
 
  BITMAPINFO info;
  ZeroMemory(&info,sizeof(BITMAPINFO));  
  info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
 
  //Get the size of the bitmap
  HDC hdc = GetDC(NULL);  
  GetDIBits(hdc, bmp, 0, 0, NULL, &info, DIB_RGB_COLORS);
 
  //allocate space for pixels
  DWORD sz = info.bmiHeader.biWidth * info.bmiHeader.biHeight * 4;
  BYTE* pPixels = (BYTE*)malloc(sizeof(BYTE)*sz);
  memset(pPixels, 0, sz);  
 
  //get pixel data in 32bit format
  info.bmiHeader.biSize = sizeof(info.bmiHeader);
  info.bmiHeader.biBitCount = 32;
  info.bmiHeader.biCompression = BI_RGB;
  info.bmiHeader.biHeight = (info.bmiHeader.biHeight < 0) ? (-info.bmiHeader.biHeight) : (info.bmiHeader.biHeight);  // correct the bottom-up ordering of lines
 
  GetDIBits(hdc, bmp, 0, info.bmiHeader.biHeight, (LPVOID)pPixels, &info, DIB_RGB_COLORS);  
 
  LONG width = info.bmiHeader.biWidth;
  LONG height = info.bmiHeader.biHeight;
 
  LONG imgSz = (info.bmiHeader.biWidth*info.bmiHeader.biHeight*(info.bmiHeader.biBitCount/8));
  ICONIMAGE ico;
  ico.Colors = info.bmiHeader.biBitCount;
  ico.Width = width;
  ico.Height = height;
 
  DWORD xorSz = 0; //not used in 32bit icons
  DWORD andSz = ico.Height * WIDTHBYTES( ico.Width );
  ico.dwNumBytes = sizeof( BITMAPINFOHEADER )
          + imgSz
          + xorSz  // XOR mask
                    + andSz; // AND mask
 
  ico.lpBits = (LPBYTE)malloc(ico.dwNumBytes);
  memset(ico.lpBits, 0, ico.dwNumBytes);
 
  // Copy the bits
    memcpy(ico.lpBits, &info.bmiHeader, sizeof(BITMAPINFOHEADER));
  memcpy(ico.lpBits + sizeof(BITMAPINFOHEADER), pPixels, imgSz);
 
    // Adjust internal pointers/variables for new image
    ico.lpbi = (LPBITMAPINFO)(ico.lpBits);    
  ico.lpXOR = ico.lpBits + sizeof(BITMAPINFOHEADER) + imgSz;
    ico.lpAND = ico.lpXOR + xorSz;
 
  if(xorSz > 0)
    memcpy( ico.lpXOR, ico.lpBits + sizeof(BITMAPINFOHEADER), xorSz );
 
  memset( ico.lpAND, 0x0, andSz );
 
  //fix bmp header for icon height, x2 required
  ico.lpbi->bmiHeader.biHeight *= 2;   
 
  free(pPixels);
 
  return ico;
}

 

And finally the function that takes a HBITMAP and a destination filepath for the target .ico file.
This function takes an array of HBITMAP’s of bmpsSz length and writes them all to a single .ico file. (there is no validation of the file path, so make sure it can be written to first and add a .ico extension)

 

C++
void ConvertBitmapToICO(HBITMAP* bmps, int bmpsSz, TCHAR* destPath)
{
 
  int entryCount = bmpsSz;
 
  //create icons from bitmaps
  ICONIMAGE* icons = (ICONIMAGE*)malloc(sizeof(ICONIMAGE) * entryCount);
  memset(icons, 0, sizeof(ICONIMAGE) * entryCount);
  for(int i=0;i<bmpsSz;i++)
  {    
    icons[i] = CreateIconImageFromBitmap(bmps[i]);
  }
 
  ICONDIR icoDir;
  icoDir.idReserved = 0;
  icoDir.idType = 1;
  icoDir.idCount = entryCount;
 
  //header
  FILE* fp = _tfopen(destPath,_T("wb"));
  fwrite(&icoDir.idReserved, sizeof(WORD), 1, fp);
  fwrite(&icoDir.idType, sizeof(WORD), 1, fp);
  fwrite(&icoDir.idCount, sizeof(WORD), 1, fp);
 
  long entriesPos = ftell(fp);
 
  //entries
  int entrySz = 16;
  ICONDIRENTRY* entries = (ICONDIRENTRY*)malloc(sizeof(ICONDIRENTRY) * entryCount);
  memset(entries, 0, sizeof(ICONDIRENTRY) * entryCount);
 
  for(int i=0;i<entrySz * entryCount;i++)
    fwrite(&entrySz,sizeof(BYTE),1, fp);
 
  //fseek(fp,entriesPos + entrySz * entryCount,SEEK_SET);
  for(int i=0;i<entryCount;i++)
  {    
    //seek to imge offset  
    entries[i].dwImageOffset = ftell(fp);
    entries[i].bWidth = icons[i].Width;
    entries[i].bHeight = icons[i].Height;
    entries[i].bColorCount = icons[i].lpbi->bmiHeader.biClrUsed;
    entries[i].wBitCount = icons[i].Colors;
    entries[i].wPlanes = 1;
 
    icons[i].lpbi->bmiHeader.biSizeImage = 0;
    //write icon image data    
    fwrite( icons[i].lpBits, icons[i].dwNumBytes, 1, fp);
    //
 
    entries[i].dwBytesInRes = ftell(fp) - entries[i].dwImageOffset;
    //
  }
 
  //fix entries
  fseek(fp, entriesPos, SEEK_SET);
  for(int i=0;i<entryCount;i++)
  {
    fwrite(&entries[i].bWidth,sizeof(BYTE), 1, fp);
    fwrite(&entries[i].bHeight,sizeof(BYTE), 1, fp);
    fwrite(&entries[i].bColorCount,sizeof(BYTE), 1, fp);
    fwrite(&entries[i].bReserved,sizeof(BYTE), 1, fp);
 
    fwrite(&entries[i].wPlanes,sizeof(WORD), 1, fp);
    fwrite(&entries[i].wBitCount,sizeof(WORD), 1, fp);
    fwrite(&entries[i].dwBytesInRes,sizeof(DWORD), 1, fp);
    fwrite(&entries[i].dwImageOffset,sizeof(DWORD), 1, fp);
  }
 
  fclose(fp);
 
 
  free(entries);
  for(int i=0;i<bmpsSz;i++)
  {
    free(icons[i].lpBits);
  }
  free(icons);
 
}

All Code is freely provided, no guarantees or warranties about its quality, use at your own risk.