Microsoft KB Archive/216638

From BetaArchive Wiki

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

Q216638



The information in this article applies to:


  • Microsoft Win32 Application Programming Interface (API), used with:
    • the operating system: Microsoft Windows 95
    • the operating system: Microsoft Windows 98
    • the operating system: Microsoft Windows Millennium Edition





SUMMARY

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

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

For additional information, click the article number below to view the 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 from Windows 95, Windows 98, or Windows Me. 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 from Windows 95, Windows 98, and Windows Me. 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) 2001 Microsoft Corporation

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

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

BOOL WINAPI ExitWindows9x(DWORD dwFlags)
{
   if (dwFlags & EWX_FORCE)
   {
   // Enumerate and terminate all processes named Explorer. This code calls 
   // the TerminateProcess API, which is usually not recommended. We must  
   // use this here, however, because Explorer's auto-restart will cause       // logoff 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 kbSDKWin32 kbOSWin95 kbOSWin98 kbFAQ kbDSupport kbGrpDSKernBase
Issue type : kbhowto
Technology : kbAudDeveloper kbWin32sSearch kbWin32API


Last Reviewed: February 24, 2001
© 2001 Microsoft Corporation. All rights reserved. Terms of Use.