Leaked source code of windows server 2003
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.

545 lines
17 KiB

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