Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

562 lines
17 KiB

  1. //*********************************************************************
  2. //* Microsoft Windows **
  3. //* Copyright (c) 1994-1998 Microsoft Corporation
  4. //*********************************************************************
  5. //
  6. // UTIL.C - common utility functions
  7. //
  8. // HISTORY:
  9. //
  10. // 96/05/22 markdu Created (from inetcfg.dll)
  11. //
  12. #include "pch.hpp"
  13. #if 0
  14. #include "string.h"
  15. #endif
  16. #define MAX_MSG_PARAM 8
  17. // function prototypes
  18. VOID _cdecl FormatErrorMessage(CHAR * pszMsg,DWORD cbMsg,CHAR * pszFmt,va_list ArgList);
  19. /*******************************************************************
  20. NAME: MsgBox
  21. SYNOPSIS: Displays a message box with the specified string ID
  22. ********************************************************************/
  23. int MsgBox(HWND hWnd,UINT nMsgID,UINT uIcon,UINT uButtons)
  24. {
  25. CHAR szMsgBuf[MAX_RES_LEN+1];
  26. CHAR szSmallBuf[SMALL_BUF_LEN+1];
  27. LoadSz(IDS_APPNAME,szSmallBuf,sizeof(szSmallBuf));
  28. LoadSz(nMsgID,szMsgBuf,sizeof(szMsgBuf));
  29. MessageBeep(uIcon);
  30. return (MessageBox(hWnd,szMsgBuf,szSmallBuf,uIcon | uButtons));
  31. }
  32. /*******************************************************************
  33. NAME: MsgBoxSz
  34. SYNOPSIS: Displays a message box with the specified text
  35. ********************************************************************/
  36. int MsgBoxSz(HWND hWnd,LPSTR szText,UINT uIcon,UINT uButtons)
  37. {
  38. CHAR szSmallBuf[SMALL_BUF_LEN+1];
  39. LoadSz(IDS_APPNAME,szSmallBuf,sizeof(szSmallBuf));
  40. MessageBeep(uIcon);
  41. return (MessageBox(hWnd,szText,szSmallBuf,uIcon | uButtons));
  42. }
  43. /*******************************************************************
  44. NAME: MsgBoxParam
  45. SYNOPSIS: Displays a message box with the specified string ID
  46. NOTES: extra parameters are string pointers inserted into nMsgID.
  47. ********************************************************************/
  48. int _cdecl MsgBoxParam(HWND hWnd,UINT nMsgID,UINT uIcon,UINT uButtons,...)
  49. {
  50. BUFFER Msg(3*MAX_RES_LEN+1); // nice n' big for room for inserts
  51. BUFFER MsgFmt(MAX_RES_LEN+1);
  52. if (!Msg || !MsgFmt) {
  53. return MsgBox(hWnd,IDS_ERROutOfMemory,MB_ICONSTOP,MB_OK);
  54. }
  55. LoadSz(nMsgID,MsgFmt.QueryPtr(),MsgFmt.QuerySize());
  56. FormatErrorMessage(Msg.QueryPtr(),Msg.QuerySize(),
  57. MsgFmt.QueryPtr(),((CHAR *) &uButtons) + sizeof(uButtons));
  58. return MsgBoxSz(hWnd,Msg.QueryPtr(),uIcon,uButtons);
  59. }
  60. /*******************************************************************
  61. NAME: LoadSz
  62. SYNOPSIS: Loads specified string resource into buffer
  63. EXIT: returns a pointer to the passed-in buffer
  64. NOTES: If this function fails (most likely due to low
  65. memory), the returned buffer will have a leading NULL
  66. so it is generally safe to use this without checking for
  67. failure.
  68. ********************************************************************/
  69. LPSTR LoadSz(UINT idString,LPSTR lpszBuf,UINT cbBuf)
  70. {
  71. ASSERT(lpszBuf);
  72. // Clear the buffer and load the string
  73. if ( lpszBuf )
  74. {
  75. *lpszBuf = '\0';
  76. LoadString( ghInstance, idString, lpszBuf, cbBuf );
  77. }
  78. return lpszBuf;
  79. }
  80. /*******************************************************************
  81. NAME: GetErrorDescription
  82. SYNOPSIS: Retrieves the text description for a given error code
  83. and class of error (standard, setupx)
  84. ********************************************************************/
  85. VOID GetErrorDescription(CHAR * pszErrorDesc,UINT cbErrorDesc,
  86. UINT uError,UINT uErrorClass)
  87. {
  88. ASSERT(pszErrorDesc);
  89. // set a leading null in error description
  90. *pszErrorDesc = '\0';
  91. switch (uErrorClass) {
  92. case ERRCLS_STANDARD:
  93. if (!FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,NULL,
  94. uError,0,pszErrorDesc,cbErrorDesc,NULL)) {
  95. // if getting system text fails, make a string a la
  96. // "error <n> occurred"
  97. CHAR szFmt[SMALL_BUF_LEN+1];
  98. LoadSz(IDS_ERRFORMAT,szFmt,sizeof(szFmt));
  99. wsprintf(pszErrorDesc,szFmt,uError);
  100. }
  101. break;
  102. case ERRCLS_SETUPX:
  103. GetSETUPXErrorText(uError,pszErrorDesc,cbErrorDesc);
  104. break;
  105. default:
  106. DEBUGTRAP("Unknown error class %lu in GetErrorDescription",
  107. uErrorClass);
  108. }
  109. }
  110. /*******************************************************************
  111. NAME: FormatErrorMessage
  112. SYNOPSIS: Builds an error message by calling FormatMessage
  113. NOTES: Worker function for PrepareErrorMessage
  114. ********************************************************************/
  115. VOID _cdecl FormatErrorMessage(CHAR * pszMsg,DWORD cbMsg,CHAR * pszFmt,va_list ArgList)
  116. {
  117. ASSERT(pszMsg);
  118. ASSERT(pszFmt);
  119. // build the message into the pszMsg buffer
  120. DWORD dwCount = FormatMessage(FORMAT_MESSAGE_FROM_STRING,
  121. pszFmt,0,0,pszMsg,cbMsg,&ArgList);
  122. ASSERT(dwCount > 0);
  123. }
  124. /*******************************************************************
  125. NAME: PrepareErrorMessage
  126. SYNOPSIS: Displays an error message for given error
  127. ENTRY: hWnd - parent window
  128. uStrID - ID of string resource with message format.
  129. Should contain %1 to be replaced by error text,
  130. additional parameters can be specified as well.
  131. uError - error code for error to display
  132. uErrorClass - ERRCLS_xxx ID of class of error that
  133. uError belongs to (standard, setupx)
  134. uIcon - icon to display
  135. ... - additional parameters to be inserted in string
  136. specified by uStrID
  137. ********************************************************************/
  138. VOID _cdecl PrepareErrorMessage(UINT uStrID,UINT uError,
  139. UINT uErrorClass,UINT uIcon,...)
  140. {
  141. // dynamically allocate buffers for messages
  142. BUFFER ErrorDesc(MAX_RES_LEN+1);
  143. BUFFER ErrorFmt(MAX_RES_LEN+1);
  144. if (!ErrorDesc || !ErrorFmt)
  145. {
  146. return;
  147. }
  148. // get a text description based on the error code and the class
  149. // of error it is
  150. GetErrorDescription(ErrorDesc.QueryPtr(),
  151. ErrorDesc.QuerySize(),uError,uErrorClass);
  152. // load the string for the message format
  153. LoadSz(uStrID,ErrorFmt.QueryPtr(),ErrorFmt.QuerySize());
  154. LPSTR args[MAX_MSG_PARAM];
  155. args[0] = (LPSTR) ErrorDesc.QueryPtr();
  156. memcpy(&args[1],((CHAR *) &uIcon) + sizeof(uIcon),(MAX_MSG_PARAM - 1) * sizeof(LPSTR));
  157. FormatErrorMessage(gpszLastErrorText, MAX_ERROR_TEXT,
  158. ErrorFmt.QueryPtr(),(va_list) &args[0]);
  159. }
  160. /*******************************************************************
  161. NAME: RunMlsetExe
  162. SYNOPSIS: Runs mlset32.exe, an Exchange app that needs to be
  163. run after files are installed otherwise Exchange
  164. barfs
  165. NOTES: We look in registry to find path to mlset32.exe
  166. ********************************************************************/
  167. DWORD RunMlsetExe(HWND hwndOwner)
  168. {
  169. DWORD dwRet = ERROR_SUCCESS;
  170. // get path to mlset32 out of registry
  171. RegEntry re(szRegPathSoftwareMicrosoft,HKEY_LOCAL_MACHINE);
  172. CHAR szAppPath[MAX_PATH+1];
  173. if (re.GetString(szRegValMlSet,szAppPath,sizeof(szAppPath))) {
  174. PROCESS_INFORMATION pi;
  175. STARTUPINFO sti;
  176. // set "SilentRunning" registry switch to make mlset32
  177. // not display the Exchange wizard
  178. RegEntry reSilent(szRegPathExchangeClientOpt,HKEY_LOCAL_MACHINE);
  179. reSilent.SetValue(szRegValSilentRunning,(DWORD) 1);
  180. ZeroMemory(&sti,sizeof(STARTUPINFO));
  181. sti.cb = sizeof(STARTUPINFO);
  182. // launch mlset32.exe
  183. BOOL fRet = CreateProcess(NULL, (LPSTR) szAppPath,
  184. NULL, NULL, FALSE, 0, NULL, NULL,
  185. &sti, &pi);
  186. if (fRet) {
  187. CloseHandle(pi.hThread);
  188. // wait for mlset to complete
  189. MsgWaitForMultipleObjectsLoop(pi.hProcess);
  190. CloseHandle(pi.hProcess);
  191. } else {
  192. dwRet = GetLastError();
  193. }
  194. // put our window in front of mlset32's
  195. SetForegroundWindow(hwndOwner);
  196. } else {
  197. dwRet = ERROR_FILE_NOT_FOUND;
  198. }
  199. return dwRet;
  200. }
  201. /*******************************************************************
  202. NAME: RemoveRunOnceEntry
  203. SYNOPSIS: Removes the specified value from setup runonce key
  204. ENTRY: uResourceID - ID of value name in resource
  205. (may be localized)
  206. ********************************************************************/
  207. VOID RemoveRunOnceEntry(UINT uResourceID)
  208. {
  209. RegEntry re(szRegPathSetupRunOnce,HKEY_LOCAL_MACHINE);
  210. CHAR szValueName[SMALL_BUF_LEN+1];
  211. ASSERT(re.GetError() == ERROR_SUCCESS);
  212. re.DeleteValue(LoadSz(uResourceID,
  213. szValueName,sizeof(szValueName)));
  214. }
  215. /*******************************************************************
  216. NAME: GenerateComputerNameIfNeeded
  217. SYNOPSIS: Makes up and stores in the registry a computer and/or
  218. workgroup name if not already set.
  219. NOTES: If we don't do this, user will get prompted for computer
  220. name and workgroup. These aren't meaningful to the user
  221. so we'll just make something up if these aren't set.
  222. ********************************************************************/
  223. BOOL GenerateComputerNameIfNeeded(VOID)
  224. {
  225. CHAR szComputerName[CNLEN+1]="";
  226. CHAR szWorkgroupName[DNLEN+1]="";
  227. BOOL fNeedToSetComputerName = FALSE;
  228. // get the computer name out of the registry
  229. RegEntry reCompName(szRegPathComputerName,HKEY_LOCAL_MACHINE);
  230. if (reCompName.GetError() == ERROR_SUCCESS) {
  231. reCompName.GetString(szRegValComputerName,szComputerName,
  232. sizeof(szComputerName));
  233. if (!lstrlen(szComputerName)) {
  234. // no computer name set! make one up
  235. GenerateDefaultName(szComputerName,sizeof(szComputerName),
  236. (CHAR *) szRegValOwner,IDS_DEF_COMPUTER_NAME);
  237. // store the generated computer name in the registry
  238. reCompName.SetValue(szRegValComputerName,szComputerName);
  239. // also need to store the computer name in the workgroup key
  240. // which we will open below... set a flag so we know to do this.
  241. // (don't ask me why they store the computer name in two places...
  242. // but we need to set both.)
  243. fNeedToSetComputerName = TRUE;
  244. }
  245. }
  246. // get the workgroup name out of the registry
  247. RegEntry reWorkgroup(szRegPathWorkgroup,HKEY_LOCAL_MACHINE);
  248. if (reWorkgroup.GetError() == ERROR_SUCCESS) {
  249. // if we set a new computer name up above, then we have to set
  250. // a 2nd copy of the new name now, in the workgroup key
  251. if (fNeedToSetComputerName) {
  252. reWorkgroup.SetValue(szRegValComputerName,szComputerName);
  253. }
  254. reWorkgroup.GetString(szRegValWorkgroup,szWorkgroupName,
  255. sizeof(szWorkgroupName));
  256. if (!lstrlen(szWorkgroupName)) {
  257. // no workgroup name set! make one up
  258. GenerateDefaultName(szWorkgroupName,sizeof(szWorkgroupName),
  259. (CHAR *) szRegValOrganization,IDS_DEF_WORKGROUP_NAME);
  260. // store the generated workgroup name in the registry
  261. reWorkgroup.SetValue(szRegValWorkgroup,szWorkgroupName);
  262. }
  263. }
  264. return TRUE;
  265. }
  266. /*******************************************************************
  267. NAME: GenerateDefaultName
  268. SYNOPSIS: Generates default computer or workgroup name
  269. ENTRY: pszName - buffer to be filled in with name
  270. cbName - size of cbName buffer
  271. pszRegValName - name of registry value in ...Windows\CurrentVersion
  272. key to generate name from
  273. uIDDefName - ID of string resource to use if no value is
  274. present in registry to generate name from
  275. ********************************************************************/
  276. BOOL GenerateDefaultName(CHAR * pszName,DWORD cbName,CHAR * pszRegValName,
  277. UINT uIDDefName)
  278. {
  279. ASSERT(pszName);
  280. ASSERT(pszRegValName);
  281. *pszName = '\0'; // NULL-terminate buffer
  282. // look for registered owner/organization name in registry
  283. RegEntry reSetup(szRegPathSetup,HKEY_LOCAL_MACHINE);
  284. if (reSetup.GetError() == ERROR_SUCCESS) {
  285. if (reSetup.GetString(pszRegValName,pszName,cbName) &&
  286. lstrlen(pszName)) {
  287. // got string from registry... now terminate at first whitespace
  288. CHAR * pch = pszName;
  289. while (*pch) {
  290. if (*pch == ' ') {
  291. // found a space, terminate here and stop
  292. *pch = '\0';
  293. } else {
  294. // advance to next char, keep going
  295. pch = CharNext(pch);
  296. }
  297. }
  298. // all done!
  299. return TRUE;
  300. }
  301. }
  302. // couldn't get this name from registry, go for our fallback name
  303. // from resource
  304. LoadSz(uIDDefName,pszName,cbName);
  305. return TRUE;
  306. }
  307. /*******************************************************************
  308. NAME: MsgWaitForMultipleObjectsLoop
  309. SYNOPSIS: Blocks until the specified object is signaled, while
  310. still dispatching messages to the main thread.
  311. ********************************************************************/
  312. DWORD MsgWaitForMultipleObjectsLoop(HANDLE hEvent)
  313. {
  314. MSG msg;
  315. DWORD dwObject;
  316. while (1)
  317. {
  318. // NB We need to let the run dialog become active so we have to half handle sent
  319. // messages but we don't want to handle any input events or we'll swallow the
  320. // type-ahead.
  321. dwObject = MsgWaitForMultipleObjects(1, &hEvent, FALSE,INFINITE, QS_ALLINPUT);
  322. // Are we done waiting?
  323. switch (dwObject) {
  324. case WAIT_OBJECT_0:
  325. case WAIT_FAILED:
  326. return dwObject;
  327. case WAIT_OBJECT_0 + 1:
  328. // got a message, dispatch it and wait again
  329. while (PeekMessage(&msg, NULL,0, 0, PM_REMOVE)) {
  330. DispatchMessage(&msg);
  331. }
  332. break;
  333. }
  334. }
  335. // never gets here
  336. }
  337. /*******************************************************************
  338. // 10/24/96 jmazner Normandy 6968
  339. // No longer neccessary thanks to Valdon's hooks for invoking ICW.
  340. NAME: SetDesktopInternetIconToBrowser
  341. SYNOPSIS: "Points" The Internet desktop icon to web browser
  342. (Internet Explorer)
  343. NOTES: The Internet icon may initially "point" at this wizard,
  344. we need to set it to launch web browser once we complete
  345. successfully.
  346. ********************************************************************/
  347. /********BOOL SetDesktopInternetIconToBrowser(VOID)
  348. {
  349. CHAR szAppPath[MAX_PATH+1]="";
  350. BOOL fRet = FALSE;
  351. // look in the app path section in registry to get path to internet
  352. // explorer
  353. RegEntry reAppPath(szRegPathIexploreAppPath,HKEY_LOCAL_MACHINE);
  354. ASSERT(reAppPath.GetError() == ERROR_SUCCESS);
  355. if (reAppPath.GetError() == ERROR_SUCCESS) {
  356. reAppPath.GetString(szNull,szAppPath,sizeof(szAppPath));
  357. ASSERT(reAppPath.GetError() == ERROR_SUCCESS);
  358. }
  359. // set the path to internet explorer as the open command for the
  360. // internet desktop icon
  361. if (lstrlen(szAppPath)) {
  362. RegEntry reIconOpenCmd(szRegPathInternetIconCommand,HKEY_CLASSES_ROOT);
  363. ASSERT(reIconOpenCmd.GetError() == ERROR_SUCCESS);
  364. if (reIconOpenCmd.GetError() == ERROR_SUCCESS) {
  365. UINT uErr = reIconOpenCmd.SetValue(szNull,szAppPath);
  366. ASSERT(uErr == ERROR_SUCCESS);
  367. fRet = (uErr == ERROR_SUCCESS);
  368. }
  369. }
  370. return fRet;
  371. }
  372. ******/
  373. /*******************************************************************
  374. NAME: PrepareForRunOnceApp
  375. SYNOPSIS: Copies wallpaper value in registry to make the runonce
  376. app happy
  377. NOTES: The runonce app (the app that displays a list of apps
  378. that are run once at startup) has a bug. At first boot,
  379. it wants to change the wallpaper from the setup wallpaper
  380. to what the user had before running setup. Setup tucks
  381. the "old" wallpaper away in a private key, then changes
  382. the wallpaper to the setup wallpaper. After the runonce
  383. app finishes, it looks in the private key to get the old
  384. wallpaper and sets that to be the current wallpaper.
  385. However, it does this all the time, not just at first boot!
  386. The end effect is that whenever you do anything that
  387. causes runonce.exe to run (add stuff thru add/remove
  388. programs control panel), your wallpaper gets set back to
  389. whatever it was when you installed win 95. This is
  390. especially bad for Plus!, since wallpaper settings are an
  391. important part of the product.
  392. To work around this bug, we copy the current wallpaper settings
  393. (which we want preserved) to setup's private key. When
  394. runonce runs it will say "aha!" and copy those values back
  395. to the current settings.
  396. ********************************************************************/
  397. VOID PrepareForRunOnceApp(VOID)
  398. {
  399. // open a key to the current wallpaper settings
  400. RegEntry reDesktop(szRegPathDesktop,HKEY_CURRENT_USER);
  401. ASSERT(reDesktop.GetError() == ERROR_SUCCESS);
  402. // open a key to the private setup section
  403. RegEntry reSetup(szRegPathSetupWallpaper,HKEY_LOCAL_MACHINE);
  404. ASSERT(reSetup.GetError() == ERROR_SUCCESS);
  405. if (reDesktop.GetError() == ERROR_SUCCESS &&
  406. reSetup.GetError() == ERROR_SUCCESS) {
  407. CHAR szWallpaper[MAX_PATH+1]="";
  408. CHAR szTiled[10]=""; // big enough for "1" + slop
  409. // get the current wallpaper name
  410. if (reDesktop.GetString(szRegValWallpaper,szWallpaper,
  411. sizeof(szWallpaper))) {
  412. // set the current wallpaper name in setup's private section
  413. UINT uRet=reSetup.SetValue(szRegValWallpaper,szWallpaper);
  414. ASSERT(uRet == ERROR_SUCCESS);
  415. // get the current 'tiled' value.
  416. reDesktop.GetString(szRegValTileWallpaper,szTiled,
  417. sizeof(szTiled));
  418. // set the 'tiled' value in setup's section
  419. if (lstrlen(szTiled)) {
  420. uRet=reSetup.SetValue(szRegValTileWallpaper,szTiled);
  421. ASSERT(uRet == ERROR_SUCCESS);
  422. }
  423. }
  424. }
  425. }