windows-nt/Source/XPSP1/NT/net/rras/cm/ccfg9x/util.cpp

563 lines
17 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
//*********************************************************************
//* 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);
}
}
}
}