Other good Win32 tips can be found here

Jim's Win32 Tips



Contents


The Elusive MLang API
For anyone running into errors when attempting to convert iso-2022-jp using MultibyteToWideChar or WideCharToMultibyte on 98, you can use the MLang COM interfaces. It's base Convert object is available on system with Internet Explorer 4.0 and above. There are also some useful Win32 API'esk entry points in 5.5 and above.

MSDN page on MLang

See Ed Batutis's excellent MLang paper for additional information.


The Un-Official .URL file format guide


A greta resource. One minor error - this doesn't mention that url files on 2K/XP systems can also be stored is Unicode files in cases where a url file contains multi-lingual characters.

The Un-Official .URL file format guide



Common Controls V6.0 in Internet Explorer Toolbars


Add the cool looking rounded buttons to your Internet Explorer toolbars. Also get your dialog interfaces supporting themes.
  • Step 1: Add the following define to your project's StdAfx.h or main header file (always before including windows.h or similar)
      #define ISOLATION_AWARE_ENABLED          1
    
  • Step 2: Add the following definition to your project's rc file
      MANIFEST_RESOURCE_ID 	RT_MANIFEST 		"myappsname.dll.manifest"
    
    For exe's it would be:
      CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST 		"myappsname.exe.manifest"
    
  • Step 3: Add the following define to your project's Resource.h file or place it above Step 2 in the rc file
     
      #define MANIFEST_RESOURCE_ID             2
    
  • Step 4: Create your manifest file ("myappsnamedll.manifest") and save it to your project's working folder
      <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
      <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
      <assemblyIdentity
          version="1.0.0.0"  (your app's version)
          processorArchitecture="x86"
          name="YourAppName"
          type="win32"
      />
      <description>Your app description here</description>
      <dependency optional="yes">
          <dependentAssembly>
              <assemblyIdentity
                  type="win32"
                  name="Microsoft.Windows.Common-Controls"
                  version="6.0.0.0"
                  processorArchitecture="X86"
                  publicKeyToken="6595b64144ccf1df"
                  language="*"
              />
          </dependentAssembly>
      </dependency>
      </assembly>
    

After compiling, the manifest should show up in your resource list (in VC6) as a compiled resource type "24". The Windows library loader will pick up the manifest (thanks to the resource id of 2) and will load Common Controls V6.0. Your toolbars should then sport the nice XP Style look and feel.

For extensions which must run on Windows 98, make sure you define your windows compile version (WINVER && _WIN32_WINNT) to 0x0400 or your interfaces will fail on creation with a windows error 126 - "The specified module can not be found."

For more information Visit this MSDN enabling_an_assembly page.


Debug versions of Wininet.dll


Hard to find, invaluable tools for debugging the deep inards of wininet communications. These dlls dump a ton of internal information into a log file as wininet goes through it's paces. You can replace the existing dll in your system directory, but this can be a pain since the shell loads it. I usually load the the debug dll manually and grab the entry points I use using GetProcAddress. Something like:
typedef HINTERNET (__stdcall *MyInternetOpen)(
    IN LPCSTR lpszAgent,
    IN DWORD dwAccessType,
    IN LPCSTR lpszProxy OPTIONAL,
    IN LPCSTR lpszProxyBypass OPTIONAL,
    IN DWORD dwFlags
    );
MyInternetOpen g_fMyInternetOpen = 0;

...

WinMain code:

HMODULE hModule;
hModule = LoadLibrary( "./wininetdbg.dll");
g_fMyInternetOpen = (MyInternetOpen)GetProcAddress( hModule, "InternetOpenA" );
Also make sure to set the debug (DWORD) value flag in the registry:
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\wininetlog = 1
Make sure to match the version of wininet your testing on to the corresponding debug version.

readme
WinInet Debug DLL 4.72.3110.0
WinInet Debug DLL 4.72.3612.1700
WinInet Debug DLL 5.00.2314.1003
WinInet Debug DLL 5.00.2614.3500
WinInet Debug DLL 5.00.2919.6305
WinInet Debug DLL 5.0.2919.6305
WinInet Debug DLL 5.0.3105.105
WinInet Debug DLL 5.50.4134.6005
WinInet Debug DLL 5.50.4807.2300
WinInet Debug DLL 6.0.2600.0000
WinInet Debug DLL 6.0.2800.1106
WinInet Debug DLL 6.0.3568.0000

I originally scouted these out while debugging a funny Wininet communication problem on Windows 98 with Internet Explorer 5.0. The issue involved making multiple SSL connection requests using Wininet's InternetOpenUrl. The second and subsequent connection requests would always fail with windows error code 12157 - "An error occurred in the secure channel support" / ERROR_WINHTTP_SECURE_CHANNEL_ERROR. In searching for a solution, I came across Dru's Win32 Tips page. The problem was related to SSLv3 on these machines and required some changes to the web server's configuration. Thanks Dru!


64-bit Shift left w/Carry and 64-bit rotate


I've been working on something for VeriSign's RFID EPC network. I came across a need for a 64-bit shift operation using MSVC's __int64's. Although .NET 2003 has 64 bit versions of _rotl and _rotr, MSVC 6.0 folks are out of luck. So I whipped up a shift left and rotate left for my project. (These aren't optimized so you can step through them in the debugger.)
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>

////////////////////////////////////////////////////////////////////////////////////
//
// ROT64 - logical 64 bit rotate left
//
////////////////////////////////////////////////////////////////////////////////////

unsigned __int64 ROT64( unsigned __int64 i64Input, int iShift )
{
  // Split the 64 bit input into two unsigned longs
  struct // little endian in memory for intel, swap for powerpc
  { 
    unsigned long right;
    unsigned long left;
  } map;

  memcpy( &map, &i64Input, sizeof(i64Input) );
  
  unsigned long rmask = 0xFFFFFFFE;
  unsigned long cmask = 0x1;

  for ( int i = 0; i < iShift; i++ )
  {
    unsigned long lcarry, lremainder;

    // Shift the left side over
    map.left = _lrotl( map.left, 1 );

    lremainder = map.left & rmask;
    lcarry = map.left & cmask; 

    unsigned long rcarry, rremainder;

    // Shift the right side over
    map.right = _lrotl( map.right, 1 );

    rremainder = map.right & rmask;
    rcarry = map.right & cmask; 

    // Set the right carry in the left remainder
    if ( rcarry == 1 ) 
      lremainder = lremainder | 0x1;
    else 
      lremainder = lremainder & rmask;

    // Set the left carry in the right remainder
    if ( lcarry == 1 ) 
      rremainder = rremainder | 0x1;
    else 
      rremainder = rremainder & rmask;

    // Store remainders
    map.left = lremainder;
    map.right = rremainder;
  }

  memcpy( &i64Input, &map, sizeof(i64Input) );
  return i64Input;
}

////////////////////////////////////////////////////////////////////////////////////
//
// SLC64 - shift left with 32 bit carry
//
// Note, you can convert the 32 bit carry to 64 bit, just remember to drop
// the carry rotation back down into SLC64 instead of using _lrotl.
//
////////////////////////////////////////////////////////////////////////////////////

unsigned __int64 SLC64( unsigned __int64 i64Input, int iShift, unsigned long * lCarry )
{
  // Split the 64 bit input into two unsigned longs
  struct // little endian in memory for intel, swap for powerpc
  { 
    unsigned long right;
    unsigned long left;
  } map;

  memcpy( &map, &i64Input, sizeof(i64Input) );
  
  unsigned long rmask = 0xFFFFFFFE;
  unsigned long cmask = 0x1;

  unsigned long carry = 0;

  for ( int i = 0; i < iShift; i++ )
  {
    unsigned long lcarry, lremainder;

    // for the loop, rotate the 32 bit carry over one
    carry = _lrotl( carry, 1 );

    // Shift the left side over
    map.left = _lrotl( map.left, 1 );

    lremainder = map.left & rmask;
    lcarry = map.left & cmask; 

    unsigned long rcarry, rremainder;

    // Shift the right side over
    map.right = _lrotl( map.right, 1 );

    rremainder = map.right & rmask;
    rcarry = map.right & cmask; 

    // Set the right carry in the left remainder
    if ( rcarry == 1 ) 
      lremainder = lremainder | 0x1;
    else 
      lremainder = lremainder & rmask;

    // Set the left carry in the carry result
    if ( lcarry == 1 ) 
      carry = carry | 0x1;
    else 
      carry = carry & rmask;

    // Clear the right lsb
    rremainder = rremainder & rmask;

    // Store remainders
    map.left = lremainder;
    map.right = rremainder;
  }

  memcpy( &i64Input, &map, sizeof(i64Input) );
  if ( lCarry ) *lCarry = carry;
  return i64Input;
}

int main(int argc, char* argv[])
{
  //unsigned __int64 i64Input = 0x8000000000000000;
  //unsigned __int64 i64Input = 0x1;
  unsigned __int64 i64Input = 0x3;
  unsigned long lCarry = 0;

  for ( int i = 0; i <= 64; i++ )
  {
    __int64 i64Tmp = SLC64( i64Input, 1, &lCarry );
    printf( "Orig=0x%016I64X Shift=0x%016I64X Carry=0x%X\n", i64Input, i64Tmp, lCarry );
    i64Input = i64Tmp;
  }

  i64Input = 0x1;
  __int64 i64Tmp = SLC64( i64Input, 64, &lCarry );
  printf( "Orig=0x%016I64X Shift=0x%016I64X Carry=0x%X\n", i64Input, i64Tmp, lCarry );

  getchar();
  return 0;
}



INTERNET_OPEN_TYPE_PRECONFIG, Proxy settings, and Windows Services
Here's a useful little note about the behavior of Wininet.dll and the INTERNET_OPEN_TYPE_PRECONFIG flag of InternetOpen for developers writing services which interact with the network. Wininet.dll pulls it's proxy information from the following registry settings:

HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings
ProxyEnabled = (DWORD) 1
ProxyServer = (String) "yourproxyserver.com:port"
ProxyOverride = (String) "<local>"

Wininet does not fall back to HKEY_LOCAL_MACHINE if these settings are not present, or allow HKEY_LOCAL_MACHINE settings to override HKEY_CURRENT_USER. If your developing a service that runs under the NETWORK SERVICE or LOCAL MACHINE accounts, these settings will not be available to Wininet and your service will fail to communicate over HTTP, HTTPS and FTP. A solution to this is to go looking for the proxy settings of other users manually.