HOWTO: Programmatically Force Windows 95 and Windows 98 to Log Off

ID: Q216638


The information in this article applies to:


SUMMARY

Because of the design of the shell, using the ExitWindowsEx() API with the EWX_FORCE flag to force a user to log off of Windows 95 or Windows 98 consistently fails. To programmatically force the user to log off, first make sure the Explorer process is closed, then call ExitWindowsEx(), specifying the EWX_LOGOFF and EWX_FORCE flags.

NOTE: The ExitWindowsEx() API is subject to intermittent failure on some rare hardware/driver configurations.

For additional information, please see the following article in the Microsoft Knowledge Base:

Q220706 INFO: ExitWindowsEx() Does Not Shut Down or Restart Win 95/98


MORE INFORMATION

In very rare situations it may be necessary to programmatically force a user to log off of Windows 95 or Windows 98. The ExitWindowsEx() API is the only shutdown API that has a force flag. Unfortunately, the combination of EWX_FORCE and EWX_LOGOFF fails to completely log off the user on Windows 95 or Windows 98. These systems behave consistently when programs call ExitWindowsEx() with these flags, resulting in the applications being terminated and the "Enter Windows Password" dialog box appearing while the user's desktop remains visible.

A program can force a user to log off by getting the process ID of Explorer, terminating it, and then calling ExitWindowsEx() with the EWX_LOGOFF and EWX_FORCE flags. The following code demonstrates this technique. Note that the ExitWindowsEx() API intermittently fails on some hardware/driver configurations.

Sample Code


/*++

  Copyright (c) 1998  Microsoft Corporation

  Module Name:

    ExitWindows9x.c

  Description:
     This sample illustrates how to force a log off on Windows 95
     and Windows 98.

--*/ 
#include<windows.h>
#include <tlhelp32.h>

BOOL WINAPI ExitWindows9x(DWORD dwFlags)
{
   if (dwFlags & EWX_FORCE)
   {
   // Enumerate and terminate all processes named Explorer.
   // This is tough, but the forced logoff is tough, and the Explorer
   // shell will cause problems.

      HINSTANCE      hInstLib;
      HANDLE         hSnapShot;
      PROCESSENTRY32 procentry;
      BOOL           bFlag;

      // ToolHelp function pointers.
      HANDLE (WINAPI *lpfCreateToolhelp32Snapshot)(DWORD,DWORD);
      BOOL (WINAPI *lpfProcess32First)(HANDLE,LPPROCESSENTRY32);
      BOOL (WINAPI *lpfProcess32Next)(HANDLE,LPPROCESSENTRY32);


      hInstLib = LoadLibraryA( "Kernel32.DLL" );
      if( hInstLib == NULL )
       return FALSE;

      // Get procedure addresses.
      // We are linking to these functions of Kernel32
      // explicitly, because otherwise a module using
      // this code would fail to load under Windows NT,
      // which does not have the Toolhelp32
      // functions in the Kernel 32.
      lpfCreateToolhelp32Snapshot=
                     (HANDLE(WINAPI *)(DWORD,DWORD))
                     GetProcAddress( hInstLib,
                     "CreateToolhelp32Snapshot" );
      lpfProcess32First=
                     (BOOL(WINAPI *)(HANDLE,LPPROCESSENTRY32))
                     GetProcAddress( hInstLib, "Process32First" );
      lpfProcess32Next=
                     (BOOL(WINAPI *)(HANDLE,LPPROCESSENTRY32))
                     GetProcAddress( hInstLib, "Process32Next" );

      if( lpfProcess32Next == NULL ||
          lpfProcess32First == NULL ||
          lpfCreateToolhelp32Snapshot == NULL )
      {
         FreeLibrary( hInstLib );
         return FALSE;
      }

      // Get a handle to a ToolHelp snapshot of the systems
      // processes.
      hSnapShot = lpfCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0 );
      if( hSnapShot == INVALID_HANDLE_VALUE )
      {
         FreeLibrary( hInstLib );
         return FALSE;
      }

      // Get the first process's information.
      procentry.dwSize = sizeof(PROCESSENTRY32);
      bFlag = lpfProcess32First( hSnapShot, &procentry );

      // While there are processes, keep looping.
      while( bFlag )
      {
         {  // We need to see if the app is named Explorer.exe.
            HANDLE hProcess;
            INT nPos;

            nPos = lstrlen(procentry.szExeFile);

            if (nPos)
            {
               while (procentry.szExeFile[--nPos] != '\\' );
               if(!lstrcmpi("explorer.exe",&(procentry.szExeFile[nPos+1])))
               {
                  // Terminate the process.
                  hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE,
                                                 procentry.th32ProcessID);
                  TerminateProcess(hProcess, 1);
                  CloseHandle(hProcess);
               }

            }
          }

         procentry.dwSize = sizeof(PROCESSENTRY32) ;
         bFlag = lpfProcess32Next( hSnapShot, &procentry );
      }

      CloseHandle(hSnapShot);

      // Free the library.
      FreeLibrary( hInstLib ) ;
   }

   return ExitWindowsEx(dwFlags,0);
}


int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
{
   ExitWindows9x(EWX_LOGOFF|EWX_FORCE);

   return TRUE;
} 

Additional query words:


Keywords          : kbAPI kbKernBase kbWinOS95 kbWinOS98 
Version           : winnt:
Platform          : winnt 
Issue type        : kbhowto 

Last Reviewed: April 3, 1999