|
|
//*********************************************************************
//* Microsoft Windows **
//* Copyright (c) 1994-1998 Microsoft Corporation
//*********************************************************************
//
// UTIL.C - common utility functions
//
// HISTORY:
//
// 96/05/22 markdu Created (from inetcfg.dll)
//
#include "pch.hpp"
#if 0
#include "string.h"
#endif
#define MAX_MSG_PARAM 8
// function prototypes
VOID _cdecl FormatErrorMessage(CHAR * pszMsg,DWORD cbMsg,CHAR * pszFmt,va_list ArgList);
/*******************************************************************
NAME: MsgBox
SYNOPSIS: Displays a message box with the specified string ID
********************************************************************/ int MsgBox(HWND hWnd,UINT nMsgID,UINT uIcon,UINT uButtons) { CHAR szMsgBuf[MAX_RES_LEN+1]; CHAR szSmallBuf[SMALL_BUF_LEN+1];
LoadSz(IDS_APPNAME,szSmallBuf,sizeof(szSmallBuf)); LoadSz(nMsgID,szMsgBuf,sizeof(szMsgBuf));
MessageBeep(uIcon); return (MessageBox(hWnd,szMsgBuf,szSmallBuf,uIcon | uButtons));
}
/*******************************************************************
NAME: MsgBoxSz
SYNOPSIS: Displays a message box with the specified text
********************************************************************/ int MsgBoxSz(HWND hWnd,LPSTR szText,UINT uIcon,UINT uButtons) { CHAR szSmallBuf[SMALL_BUF_LEN+1]; LoadSz(IDS_APPNAME,szSmallBuf,sizeof(szSmallBuf));
MessageBeep(uIcon); return (MessageBox(hWnd,szText,szSmallBuf,uIcon | uButtons)); }
/*******************************************************************
NAME: MsgBoxParam
SYNOPSIS: Displays a message box with the specified string ID
NOTES: extra parameters are string pointers inserted into nMsgID.
********************************************************************/ int _cdecl MsgBoxParam(HWND hWnd,UINT nMsgID,UINT uIcon,UINT uButtons,...) { BUFFER Msg(3*MAX_RES_LEN+1); // nice n' big for room for inserts
BUFFER MsgFmt(MAX_RES_LEN+1);
if (!Msg || !MsgFmt) { return MsgBox(hWnd,IDS_ERROutOfMemory,MB_ICONSTOP,MB_OK); }
LoadSz(nMsgID,MsgFmt.QueryPtr(),MsgFmt.QuerySize());
FormatErrorMessage(Msg.QueryPtr(),Msg.QuerySize(), MsgFmt.QueryPtr(),((CHAR *) &uButtons) + sizeof(uButtons));
return MsgBoxSz(hWnd,Msg.QueryPtr(),uIcon,uButtons); }
/*******************************************************************
NAME: LoadSz
SYNOPSIS: Loads specified string resource into buffer
EXIT: returns a pointer to the passed-in buffer
NOTES: If this function fails (most likely due to low memory), the returned buffer will have a leading NULL so it is generally safe to use this without checking for failure.
********************************************************************/ LPSTR LoadSz(UINT idString,LPSTR lpszBuf,UINT cbBuf) { ASSERT(lpszBuf);
// Clear the buffer and load the string
if ( lpszBuf ) { *lpszBuf = '\0'; LoadString( ghInstance, idString, lpszBuf, cbBuf ); } return lpszBuf; }
/*******************************************************************
NAME: GetErrorDescription
SYNOPSIS: Retrieves the text description for a given error code and class of error (standard, setupx)
********************************************************************/ VOID GetErrorDescription(CHAR * pszErrorDesc,UINT cbErrorDesc, UINT uError,UINT uErrorClass) { ASSERT(pszErrorDesc);
// set a leading null in error description
*pszErrorDesc = '\0'; switch (uErrorClass) {
case ERRCLS_STANDARD:
if (!FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,NULL, uError,0,pszErrorDesc,cbErrorDesc,NULL)) { // if getting system text fails, make a string a la
// "error <n> occurred"
CHAR szFmt[SMALL_BUF_LEN+1]; LoadSz(IDS_ERRFORMAT,szFmt,sizeof(szFmt)); wsprintf(pszErrorDesc,szFmt,uError); }
break;
case ERRCLS_SETUPX:
GetSETUPXErrorText(uError,pszErrorDesc,cbErrorDesc); break;
default:
DEBUGTRAP("Unknown error class %lu in GetErrorDescription", uErrorClass);
}
} /*******************************************************************
NAME: FormatErrorMessage
SYNOPSIS: Builds an error message by calling FormatMessage
NOTES: Worker function for PrepareErrorMessage
********************************************************************/ VOID _cdecl FormatErrorMessage(CHAR * pszMsg,DWORD cbMsg,CHAR * pszFmt,va_list ArgList) { ASSERT(pszMsg); ASSERT(pszFmt);
// build the message into the pszMsg buffer
DWORD dwCount = FormatMessage(FORMAT_MESSAGE_FROM_STRING, pszFmt,0,0,pszMsg,cbMsg,&ArgList); ASSERT(dwCount > 0); }
/*******************************************************************
NAME: PrepareErrorMessage
SYNOPSIS: Displays an error message for given error
ENTRY: hWnd - parent window uStrID - ID of string resource with message format. Should contain %1 to be replaced by error text, additional parameters can be specified as well. uError - error code for error to display uErrorClass - ERRCLS_xxx ID of class of error that uError belongs to (standard, setupx) uIcon - icon to display ... - additional parameters to be inserted in string specified by uStrID
********************************************************************/ VOID _cdecl PrepareErrorMessage(UINT uStrID,UINT uError, UINT uErrorClass,UINT uIcon,...) { // dynamically allocate buffers for messages
BUFFER ErrorDesc(MAX_RES_LEN+1); BUFFER ErrorFmt(MAX_RES_LEN+1);
if (!ErrorDesc || !ErrorFmt) { return; }
// get a text description based on the error code and the class
// of error it is
GetErrorDescription(ErrorDesc.QueryPtr(), ErrorDesc.QuerySize(),uError,uErrorClass);
// load the string for the message format
LoadSz(uStrID,ErrorFmt.QueryPtr(),ErrorFmt.QuerySize());
LPSTR args[MAX_MSG_PARAM]; args[0] = (LPSTR) ErrorDesc.QueryPtr(); memcpy(&args[1],((CHAR *) &uIcon) + sizeof(uIcon),(MAX_MSG_PARAM - 1) * sizeof(LPSTR));
FormatErrorMessage(gpszLastErrorText, MAX_ERROR_TEXT, ErrorFmt.QueryPtr(),(va_list) &args[0]); }
/*******************************************************************
NAME: RunMlsetExe
SYNOPSIS: Runs mlset32.exe, an Exchange app that needs to be run after files are installed otherwise Exchange barfs
NOTES: We look in registry to find path to mlset32.exe
********************************************************************/ DWORD RunMlsetExe(HWND hwndOwner) { DWORD dwRet = ERROR_SUCCESS;
// get path to mlset32 out of registry
RegEntry re(szRegPathSoftwareMicrosoft,HKEY_LOCAL_MACHINE);
CHAR szAppPath[MAX_PATH+1]; if (re.GetString(szRegValMlSet,szAppPath,sizeof(szAppPath))) { PROCESS_INFORMATION pi; STARTUPINFO sti;
// set "SilentRunning" registry switch to make mlset32
// not display the Exchange wizard
RegEntry reSilent(szRegPathExchangeClientOpt,HKEY_LOCAL_MACHINE); reSilent.SetValue(szRegValSilentRunning,(DWORD) 1);
ZeroMemory(&sti,sizeof(STARTUPINFO)); sti.cb = sizeof(STARTUPINFO); // launch mlset32.exe
BOOL fRet = CreateProcess(NULL, (LPSTR) szAppPath, NULL, NULL, FALSE, 0, NULL, NULL, &sti, &pi); if (fRet) { CloseHandle(pi.hThread);
// wait for mlset to complete
MsgWaitForMultipleObjectsLoop(pi.hProcess);
CloseHandle(pi.hProcess); } else { dwRet = GetLastError(); }
// put our window in front of mlset32's
SetForegroundWindow(hwndOwner); } else { dwRet = ERROR_FILE_NOT_FOUND; }
return dwRet; }
/*******************************************************************
NAME: RemoveRunOnceEntry
SYNOPSIS: Removes the specified value from setup runonce key
ENTRY: uResourceID - ID of value name in resource (may be localized)
********************************************************************/ VOID RemoveRunOnceEntry(UINT uResourceID) { RegEntry re(szRegPathSetupRunOnce,HKEY_LOCAL_MACHINE); CHAR szValueName[SMALL_BUF_LEN+1]; ASSERT(re.GetError() == ERROR_SUCCESS); re.DeleteValue(LoadSz(uResourceID, szValueName,sizeof(szValueName))); }
/*******************************************************************
NAME: GenerateComputerNameIfNeeded
SYNOPSIS: Makes up and stores in the registry a computer and/or workgroup name if not already set.
NOTES: If we don't do this, user will get prompted for computer name and workgroup. These aren't meaningful to the user so we'll just make something up if these aren't set.
********************************************************************/ BOOL GenerateComputerNameIfNeeded(VOID) { CHAR szComputerName[CNLEN+1]=""; CHAR szWorkgroupName[DNLEN+1]=""; BOOL fNeedToSetComputerName = FALSE;
// get the computer name out of the registry
RegEntry reCompName(szRegPathComputerName,HKEY_LOCAL_MACHINE); if (reCompName.GetError() == ERROR_SUCCESS) { reCompName.GetString(szRegValComputerName,szComputerName, sizeof(szComputerName)); if (!lstrlen(szComputerName)) { // no computer name set! make one up
GenerateDefaultName(szComputerName,sizeof(szComputerName), (CHAR *) szRegValOwner,IDS_DEF_COMPUTER_NAME); // store the generated computer name in the registry
reCompName.SetValue(szRegValComputerName,szComputerName);
// also need to store the computer name in the workgroup key
// which we will open below... set a flag so we know to do this.
// (don't ask me why they store the computer name in two places...
// but we need to set both.)
fNeedToSetComputerName = TRUE; } }
// get the workgroup name out of the registry
RegEntry reWorkgroup(szRegPathWorkgroup,HKEY_LOCAL_MACHINE); if (reWorkgroup.GetError() == ERROR_SUCCESS) {
// if we set a new computer name up above, then we have to set
// a 2nd copy of the new name now, in the workgroup key
if (fNeedToSetComputerName) { reWorkgroup.SetValue(szRegValComputerName,szComputerName); }
reWorkgroup.GetString(szRegValWorkgroup,szWorkgroupName, sizeof(szWorkgroupName)); if (!lstrlen(szWorkgroupName)) { // no workgroup name set! make one up
GenerateDefaultName(szWorkgroupName,sizeof(szWorkgroupName), (CHAR *) szRegValOrganization,IDS_DEF_WORKGROUP_NAME); // store the generated workgroup name in the registry
reWorkgroup.SetValue(szRegValWorkgroup,szWorkgroupName); } }
return TRUE; }
/*******************************************************************
NAME: GenerateDefaultName
SYNOPSIS: Generates default computer or workgroup name
ENTRY: pszName - buffer to be filled in with name cbName - size of cbName buffer pszRegValName - name of registry value in ...Windows\CurrentVersion key to generate name from uIDDefName - ID of string resource to use if no value is present in registry to generate name from
********************************************************************/ BOOL GenerateDefaultName(CHAR * pszName,DWORD cbName,CHAR * pszRegValName, UINT uIDDefName) { ASSERT(pszName); ASSERT(pszRegValName);
*pszName = '\0'; // NULL-terminate buffer
// look for registered owner/organization name in registry
RegEntry reSetup(szRegPathSetup,HKEY_LOCAL_MACHINE); if (reSetup.GetError() == ERROR_SUCCESS) { if (reSetup.GetString(pszRegValName,pszName,cbName) && lstrlen(pszName)) { // got string from registry... now terminate at first whitespace
CHAR * pch = pszName; while (*pch) { if (*pch == ' ') { // found a space, terminate here and stop
*pch = '\0'; } else { // advance to next char, keep going
pch = CharNext(pch); } } // all done!
return TRUE; } } // couldn't get this name from registry, go for our fallback name
// from resource
LoadSz(uIDDefName,pszName,cbName); return TRUE; }
/*******************************************************************
NAME: MsgWaitForMultipleObjectsLoop
SYNOPSIS: Blocks until the specified object is signaled, while still dispatching messages to the main thread.
********************************************************************/ DWORD MsgWaitForMultipleObjectsLoop(HANDLE hEvent) { MSG msg; DWORD dwObject; while (1) { // NB We need to let the run dialog become active so we have to half handle sent
// messages but we don't want to handle any input events or we'll swallow the
// type-ahead.
dwObject = MsgWaitForMultipleObjects(1, &hEvent, FALSE,INFINITE, QS_ALLINPUT); // Are we done waiting?
switch (dwObject) { case WAIT_OBJECT_0: case WAIT_FAILED: return dwObject;
case WAIT_OBJECT_0 + 1: // got a message, dispatch it and wait again
while (PeekMessage(&msg, NULL,0, 0, PM_REMOVE)) { DispatchMessage(&msg); } break; } } // never gets here
}
/*******************************************************************
// 10/24/96 jmazner Normandy 6968
// No longer neccessary thanks to Valdon's hooks for invoking ICW.
NAME: SetDesktopInternetIconToBrowser
SYNOPSIS: "Points" The Internet desktop icon to web browser (Internet Explorer)
NOTES: The Internet icon may initially "point" at this wizard, we need to set it to launch web browser once we complete successfully.
********************************************************************/ /********BOOL SetDesktopInternetIconToBrowser(VOID)
{ CHAR szAppPath[MAX_PATH+1]=""; BOOL fRet = FALSE;
// look in the app path section in registry to get path to internet
// explorer
RegEntry reAppPath(szRegPathIexploreAppPath,HKEY_LOCAL_MACHINE); ASSERT(reAppPath.GetError() == ERROR_SUCCESS); if (reAppPath.GetError() == ERROR_SUCCESS) {
reAppPath.GetString(szNull,szAppPath,sizeof(szAppPath)); ASSERT(reAppPath.GetError() == ERROR_SUCCESS);
}
// set the path to internet explorer as the open command for the
// internet desktop icon
if (lstrlen(szAppPath)) { RegEntry reIconOpenCmd(szRegPathInternetIconCommand,HKEY_CLASSES_ROOT); ASSERT(reIconOpenCmd.GetError() == ERROR_SUCCESS); if (reIconOpenCmd.GetError() == ERROR_SUCCESS) { UINT uErr = reIconOpenCmd.SetValue(szNull,szAppPath); ASSERT(uErr == ERROR_SUCCESS); fRet = (uErr == ERROR_SUCCESS); } }
return fRet; } ******/
/*******************************************************************
NAME: PrepareForRunOnceApp
SYNOPSIS: Copies wallpaper value in registry to make the runonce app happy
NOTES: The runonce app (the app that displays a list of apps that are run once at startup) has a bug. At first boot, it wants to change the wallpaper from the setup wallpaper to what the user had before running setup. Setup tucks the "old" wallpaper away in a private key, then changes the wallpaper to the setup wallpaper. After the runonce app finishes, it looks in the private key to get the old wallpaper and sets that to be the current wallpaper. However, it does this all the time, not just at first boot! The end effect is that whenever you do anything that causes runonce.exe to run (add stuff thru add/remove programs control panel), your wallpaper gets set back to whatever it was when you installed win 95. This is especially bad for Plus!, since wallpaper settings are an important part of the product.
To work around this bug, we copy the current wallpaper settings (which we want preserved) to setup's private key. When runonce runs it will say "aha!" and copy those values back to the current settings.
********************************************************************/ VOID PrepareForRunOnceApp(VOID) { // open a key to the current wallpaper settings
RegEntry reDesktop(szRegPathDesktop,HKEY_CURRENT_USER); ASSERT(reDesktop.GetError() == ERROR_SUCCESS);
// open a key to the private setup section
RegEntry reSetup(szRegPathSetupWallpaper,HKEY_LOCAL_MACHINE); ASSERT(reSetup.GetError() == ERROR_SUCCESS);
if (reDesktop.GetError() == ERROR_SUCCESS && reSetup.GetError() == ERROR_SUCCESS) { CHAR szWallpaper[MAX_PATH+1]=""; CHAR szTiled[10]=""; // big enough for "1" + slop
// get the current wallpaper name
if (reDesktop.GetString(szRegValWallpaper,szWallpaper, sizeof(szWallpaper))) {
// set the current wallpaper name in setup's private section
UINT uRet=reSetup.SetValue(szRegValWallpaper,szWallpaper); ASSERT(uRet == ERROR_SUCCESS);
// get the current 'tiled' value.
reDesktop.GetString(szRegValTileWallpaper,szTiled, sizeof(szTiled));
// set the 'tiled' value in setup's section
if (lstrlen(szTiled)) { uRet=reSetup.SetValue(szRegValTileWallpaper,szTiled); ASSERT(uRet == ERROR_SUCCESS); } } } }
|