Your SQL Server Desktop Engine installation may stop responding when you use the WaitForSingleObject function in a Win32 bootstrap wrapper application (841061)



The information in this article applies to:

  • Microsoft SQL Server 2000 Desktop Engine (MSDE)

SYMPTOMS

When you install Microsoft SQL Server 2000 Desktop Engine (also known as MSDE 2000) and other third-party applications by using a Win32 bootstrap wrapper application, and your bootstrap application calls the WaitForSingleObject function with the time-out interval parameter set to INFINITE, the application may stop responding.

CAUSE

This problem occurs because during the installation of SQL Server Desktop Engine, executable files such as Sqlredis.exe and Setupre.exe communicate their progress by broadcasting messages to all top-level windows. Because the messages are sent synchronously, if the calling application owns a top-level window and is not processing the messages that are sent to its message loop, the installation process may stop responding until the application quits.

WORKAROUND

To work around this problem, you must call the MsgWaitForMultipleObjects function in a message loop to process the window messages that are posted by different executable files to the top-level windows.

Microsoft provides programming examples for illustration only, without warranty either expressed or implied. This includes, but is not limited to, the implied warranties of merchantability or fitness for a particular purpose. This article assumes that you are familiar with the programming language that is being demonstrated and with the tools that are used to create and to debug procedures. Microsoft support engineers can help explain the functionality of a particular procedure, but they will not modify these examples to provide added functionality or construct procedures to meet your specific requirements.

Note You must assign a strong password to the sa account when you install any instance of SQL Server Desktop Engine. You must do this even if the instance uses Windows authentication mode. You must pass the generated password as a command-line parameter to the CreateProcess function. For additional information about how to specify a strong sa password when you install SQL Server Desktop Engine, click the following article number to view the article in the Microsoft Knowledge Base:

814463 How to specify a strong sa password when you install SQL Server 2000 Desktop Engine (MSDE 2000)

To call the MsgWaitForMultipleObjects function in a message loop, follow these steps:
  1. Start Microsoft Visual Studio .NET 2003.
  2. On the File menu, point to New, and then click Project.
  3. Under Project Types, click Visual C++ Projects, and then click Win32 Project under Templates.
  4. In the Name box, type win32bootstrap, and then click OK.
  5. In the Win32 Application Wizard - Win32bootstrap dialog box, click Finish.
  6. In Solution Explorer, double-click Win32bootstrap.cpp under Source Files.
  7. Add the following code to the end of the Win32bootstrap.cpp file:
    int DoMSDEInstall(HWND hWnd)
    {
    	int iResult = 1; 				// You can also use whatever app logic for error control requires
    	TCHAR msgText[256];			// Informational message buffer
    	TCHAR msgCaption[] = _T("Information");	// Message Box caption
    	UINT msgType = MB_ICONEXCLAMATION;	// Message Box type spec
    	DWORD dwECode;				// Exit code from the SQL Server Desktop Engine Setup process
    	MSG msg;					// Message to peek and process
    
    	STARTUPINFO si = { sizeof(si) };
    	PROCESS_INFORMATION pi;
    
    	// Specify the complete path of the Setup.exe file.
    	// You must add code to specify a strong sa password
    	// as specified in 814463.
    	TCHAR szCommandLine[] = TEXT("setup.exe SAPWD=SomePassword REBOOT=ReallySuppress");
    
    	// Start the SQL Server Desktop Engine Setup process by sending the appropriate parameters.
    	// You must customize this code according to your installation requirements.
    	BOOL fSuccess = CreateProcess(NULL, szCommandLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
    
    	if (fSuccess)
    	{
    		CloseHandle(pi.hThread);
    		// The following code replaces the call to
    		// WaitForSingleObject(pi.hProcess, INFINITE);
    		while (1) 
    		{
    			while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) 
    			{
    				TranslateMessage(&msg);
    				// If it is a quit message, exit.
    				if (msg.message == WM_QUIT)  
    					return 1; 
    				// Otherwise, dispatch the message.
    				DispatchMessage (&msg); 
    			}
    			// Wait for any message that is sent to or is posted to this queue 
    			// or for the process handle to be signaled.
    			if (MsgWaitForMultipleObjects (1, &pi.hProcess, 
    				FALSE, 1000, QS_ALLINPUT) == WAIT_OBJECT_0)
    				break;
    		}
    		GetExitCodeProcess(pi.hProcess, &dwECode);
    		CloseHandle(pi.hProcess);
    	}
    
      wsprintf(msgText, _T("Exit Code is %d"), dwECode);
      MessageBox(hWnd, msgText, msgCaption, msgType);
    
      return iResult;
    }
    
    void DisplayError (DWORD dwError)
    {
    	//Resolve the error code to a message string.
    	LPCTSTR MessageBuffer;
    	DWORD dwBufferLength = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
    		NULL, // module to get message from (NULL == system)
    		dwError,
    		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language.
    		(LPTSTR) &MessageBuffer,
    		0,
    		NULL
    		);
    
    	DWORD dwBytesWritten;
    	// Output message string on stderr.
    	WriteFile(
    		GetStdHandle(STD_ERROR_HANDLE),
    		MessageBuffer,
    		dwBufferLength,
    		&dwBytesWritten,
    		NULL
    		);
    }
  8. Add the following function declarations at the top of the code window after the other forward function declarations:
    int DoMSDEInstall(HWND hWnd);
    void DisplayError (DWORD);
  9. Add code to call the newly added functions from an appropriate location, according to your installation requirements. For example, add the following code inside the Main message loop of the _tWinMain function to start the SQL Server Desktop Engine installation and to start the third-party (or custom) application installation:
    DWORD dwRes = 0;
    // Call the SQL Server Desktop Engine installation function.
    if (!DoMSDEInstall(msg.hwnd))
    {
    	//Failed to install SQL Server Desktop Engine, log the error and return failure.
    	dwRes = GetLastError();
    	DisplayError(dwRes);
    	return dwRes;
    }
    
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    
    ZeroMemory( &si, sizeof(si) );
    si.cb = sizeof(si);
    ZeroMemory( &pi, sizeof(pi) );
    
    //Start the custom application installation or the third-party application installation. 
    // Provide the correct path of the executable file and the appropriate parameters.
    CreateProcess(_T("Myappsetup.exe"), NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
    
    return 0;
    Note You must customize this sample code according to your installation requirements.
  10. On the File menu, click Save All to save all the files.
  11. On the Build menu, click Rebuild Solution.
You can also work around this problem by using a console bootstrap wrapper application to install SQL Server Desktop Engine. To do this, follow these steps:
  1. Start Visual Studio .NET 2003.
  2. On the File menu, point to New, and then click Project.
  3. Under Project Types, click Visual C++ Projects, and then click Win32 Console Project under Templates.
  4. In the Name box, type consolebootstrap, and then click OK.
  5. In the Win32 Application Wizard - Consolebootstrap dialog box, click Finish.
  6. In Solution Explorer, double-click Consolebootstrap.cpp under Source Files.
  7. Replace the code in the Consolebootstrap.cpp file with the following code:
    #pragma once
    #include "stdafx.h"
    #include <stdio.h>
    #include <atlenc.h>
    
    #define SAPWDSWITCH _T("SAPWD=")
    #define INSTANCENAME _T("INSTANCENAME=MSDETEST")
    
    void DisplayError (DWORD);
    
    int main(void)
    {	
    	DWORD dwRes = 0;
    	STARTUPINFO si;
    	PROCESS_INFORMATION pi;
    	
    	ZeroMemory( &si, sizeof(si) );
    	si.cb = sizeof(si);
    	ZeroMemory( &pi, sizeof(pi) );
    
    	// Specify the complete path of the Setup.exe file.
    	// You must add code to specify a strong sa password
    	// as specified in 814463.
    	TCHAR szCommandLine[] = TEXT("setup.exe SAPWD=SomePassword REBOOT=ReallySuppress");
    
    	// Start the SQL Server Desktop Engine Setup process by sending the appropriate parameters.
    	// You must customize this code according to your installation requirements.
    	if (!CreateProcess(NULL, szCommandLine, NULL, NULL, FALSE, 
    				0, NULL, NULL, &si, &pi))
    	{
    		dwRes = GetLastError();
    		DisplayError(dwRes);
    		return 0;
    	}
    	
    	// Close main thread handle first.
    	CloseHandle(pi.hThread);
    	//
    	//Wait for the SQL Server Desktop Engine Setup to return.
    	// Important This call only works for the console application type.
    	// If you are using a Win32 project, use MsgWaitForMultipleObjects() instead of WaitForSingleObject().
    	//
    	WaitForSingleObject(pi.hProcess, INFINITE);
    
    	// Close the process handle.
    	CloseHandle(pi.hProcess);
    	//
    
     	ZeroMemory( &si, sizeof(si) );
        	si.cb = sizeof(si);
        	ZeroMemory( &pi, sizeof(pi) );
    
    	//Start the custom application installation or the third-party application installation.
    	//Provide the correct path of the executable file and the appropriate parameters.
    	CreateProcess(_T("Myappsetup.exe"), NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
    
    	return 0;
    }
    
    void DisplayError (DWORD dwError)
    {
    	//Resolve the error code to a message string.
    	LPCTSTR MessageBuffer;
    	DWORD dwBufferLength = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
    		NULL, // module to get message from (NULL == system)
    		dwError,
    		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language.
    		(LPTSTR) &MessageBuffer,
    		0,
    		NULL
    		);
    
    	DWORD dwBytesWritten;
    	// Output message string on stderr.
    	WriteFile(
    		GetStdHandle(STD_ERROR_HANDLE),
    		MessageBuffer,
    		dwBufferLength,
    		&dwBytesWritten,
    		NULL
    		);
    }
  8. On the File menu, click Save All to save all the files.
  9. On the Build menu, click Rebuild Solution.

REFERENCES

For additional information about this problem, click the following article numbers to view the articles in the Microsoft Knowledge Base:

247221 PRB: Unattended install of SQL Server 7.0 or MSDE 1.0 stops responding

824042 PRB: The SQL Server Desktop Engine Setup program may stop responding when it is started from an external application

For additional information about SQL Server Desktop Engine installation, deployment, and patching, click the following article number to view the article in the Microsoft Knowledge Base:

817788 Support WebCast: Microsoft SQL Server 2000 Desktop Engine (MSDE) installation, deployment, and patching


Modification Type:MajorLast Reviewed:7/5/2005
Keywords:kbsetup kbConsole kbAuthentication kbAppSetup kbhowto kbcode kbinfo KB841061 kbAudDeveloper