I was working on a headless system recently and wanted to run cemgrc.exe when a network connection was made. That inspired me to write a little application to do it.
I decided to make the application flexible, so I added a few requirements; be able to run from HKEY_LOCAL_MACHINE\Init, and read the application name and command line from the registry.
Working backward, I wrote a function to read the registry to get the application name and command line and then start the application using CreateProcess(). Regular readers of this blog will recognize most of this code from Windows CE: Reading a String from the Registry.
void StartApp()
{
      TCHAR *AppName = NULL;
      TCHAR *CommandLine = NULL;
      DWORD Result;
      HKEY hKey;
      DWORD NumBytes = 0;
      DWORD Type;
      PROCESS_INFORMATION pi;
 
      // Open the Registry Key
      Result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, NETWORK_START_APP_KEY, 0, 0, &hKey);
 
      if( ERROR_SUCCESS == Result )
      {
            // This is a fake read, all it does is fill in NumBytes with the number of
            // bytes in the string value plus the null character.
            Result = RegQueryValueEx( hKey, NETWORK_START_APP_NAME, NULL, &Type, NULL, &NumBytes );
            if( NumBytes > 0 )
            {
                  // Now we know how big the string is allocate and read it
                  AppName = (TCHAR *)malloc( NumBytes );
                  if( AppName != NULL )
                  Result = RegQueryValueEx( hKey, NETWORK_START_APP_NAME, NULL, &Type,
                                                            (LPBYTE)AppName, &NumBytes );
            }
            // This is a fake read, all it does is fill in NumBytes with the number of
            // bytes in the string value plus the null character.
            Result = RegQueryValueEx( hKey, NETWORK_START_APP_COMMANDLINE, NULL, &Type, NULL, &NumBytes );
            if( NumBytes > 0 )
            {
                  // Now we know how big the string is allocate and read it
                  CommandLine = (TCHAR *)malloc( NumBytes );
                  if( CommandLine != NULL )
                  Result = RegQueryValueEx( hKey, NETWORK_START_APP_COMMANDLINE, NULL, &Type,
                                                            (LPBYTE)CommandLine, &NumBytes );
            }
            RegCloseKey( hKey );
 
            if( CreateProcess( AppName, CommandLine, NULL, NULL, FALSE, 0, NULL, NULL, NULL, &pi))
            {
                  CloseHandle(pi.hProcess);
                  CloseHandle(pi.hThread);
            }
            else
            {
                  RETAILMSG( 1, (TEXT("Failed to start app: %s error %d\n"), AppName, GetLastError() ));
            }
 
            free( AppName );
            free( CommandLine );
      }
}
StartApp() is really the meat of this application, now we just need to determine if we are running because of a network connection or not and we need to register for network notifications. I do all of this in WinMain():
int WINAPI WinMain( HINSTANCE hInstance,
                    HINSTANCE hPrevInstance,
                    LPTSTR    lpCmdLine,
                    int       nCmdShow)
{
    TCHAR Path[MAX_PATH];
      HANDLE hMutex;
 
    GetModuleFileName( hInstance, Path, MAX_PATH );
      hMutex = CreateMutex(NULL, TRUE, Path);
      if (GetLastError() == ERROR_ALREADY_EXISTS){
            RETAILMSG(1, (TEXT("%s is running already\r\n"), Path));
            return 0;
      }
     
      if( lpCmdLine && 0 != wcscmp(lpCmdLine, TEXT("AppRunAtNetConnect")) )
      {
            if( !CeRunAppAtEvent(Path, NOTIFICATION_EVENT_NET_CONNECT) )
                  RETAILMSG(1, (TEXT("Could not register for notifications\r\n")));
            SignalStarted( _wtol(lpCmdLine) );
      }
      else
      {
            StartApp();
            // Okay this is maybe wrong, but it prevents running again if we
            // are run more than once on a network connection
            Sleep( 5000 );
      }
 
      return 1;
}
Note that if this isn’t a network connection, then the code calls CeRunAppAtEvent() to register for network notifications and calls SignalStarted() in case the application was started from HKEY_LOCAL_MACHINE\Init.
This file includes and defines the following:
#include <windows.h>
#include <commctrl.h>
#include <notify.h>
 
#define NETWORK_START_APP_KEY (TEXT("Software\\NetworkLauncher"))
#define NETWORK_START_APP_NAME      (TEXT("AppName"))
#define NETWORK_START_APP_COMMANDLINE     (TEXT("CommandLine"))
 
And now when a network connection is made, I can start cemgrc.exe.
 
Copyright © 2010 – Bruce Eitman
All Rights Reserved