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.

794 lines
26 KiB

  1. #include "grpconv.h"
  2. #include "util.h"
  3. #include "rcids.h"
  4. #include "group.h"
  5. #include "gcinst.h"
  6. #include <shellp.h>
  7. #include <windowsx.h>
  8. #include <regstr.h>
  9. // we only call ImmDisableIME if we can sucessfully LoadLibrary
  10. // and GetProcAddress it, since this function did not exist on NT4
  11. // and win95.
  12. extern BOOL WINAPI ImmDisableIME(DWORD);
  13. //---------------------------------------------------------------------------
  14. // Global to this file only...
  15. const TCHAR g_szGRP[] = TEXT("grp");
  16. const TCHAR c_szClassInfo[] = STRINI_CLASSINFO;
  17. const TCHAR g_szMSProgramGroup[] = TEXT("MSProgramGroup");
  18. const TCHAR g_szSpacePercentOne[] = TEXT(" %1");
  19. const TCHAR c_szGroups[] = TEXT("Groups");
  20. const TCHAR c_szSettings[] = TEXT("Settings");
  21. const TCHAR c_szWindow[] = TEXT("Window");
  22. const TCHAR c_szNULL[] = TEXT("");
  23. const TCHAR c_szRegGrpConv[] = REGSTR_PATH_GRPCONV;
  24. const TCHAR c_szCLSID[] = TEXT("CLSID");
  25. const CHAR c_szReporter[] = "reporter.exe -q";
  26. const TCHAR c_szCheckAssociations[] = TEXT("CheckAssociations");
  27. const TCHAR c_szRegExplorer[] = REGSTR_PATH_EXPLORER;
  28. const TCHAR c_szDotDoc[] = TEXT(".doc");
  29. const TCHAR c_szWordpadDocument[] = TEXT("wordpad.document");
  30. const TCHAR c_szWordpadDocumentOne[] = TEXT("wordpad.document.1");
  31. const TCHAR c_szUnicodeGroups[] = TEXT("UNICODE Program Groups");
  32. const TCHAR c_szAnsiGroups[] = TEXT("Program Groups");
  33. const TCHAR c_szCommonGroups[] = TEXT("SOFTWARE\\Program Groups");
  34. HKEY g_hkeyGrpConv;
  35. //---------------------------------------------------------------------------
  36. // Global to the app...
  37. HINSTANCE g_hinst;
  38. TCHAR g_szStartGroup[MAXGROUPNAMELEN + 1];
  39. UINT GC_TRACE = 0; // Default no tracing
  40. BOOL g_fShowUI = TRUE;
  41. // Forward declarations
  42. int WinMainT(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow);
  43. //---------------------------------------------------------------------------
  44. BOOL InitApplication(HINSTANCE hInstance)
  45. {
  46. TCHAR szTypeName[CCHSZNORMAL];
  47. TCHAR szPath[MAX_PATH];
  48. // Register this app as being able to handle progman groups.
  49. LoadString(hInstance, IDS_GROUPTYPENAME, szTypeName, ARRAYSIZE(szTypeName));
  50. // Get the path to this app.
  51. GetModuleFileName(hInstance, szPath, ARRAYSIZE(szPath));
  52. // Tag on the percent one thingy.
  53. lstrcat(szPath, g_szSpacePercentOne);
  54. // Regsiter the app.
  55. ShellRegisterApp(g_szGRP, g_szMSProgramGroup, szTypeName, szPath, TRUE);
  56. // Explorer key.
  57. RegCreateKey(HKEY_CURRENT_USER, c_szRegGrpConv, &g_hkeyGrpConv);
  58. Log(TEXT("Init Application."));
  59. return TRUE;
  60. }
  61. //---------------------------------------------------------------------------
  62. void UnInitApplication(void)
  63. {
  64. Log(TEXT("Uninit Application."));
  65. if (g_hkeyGrpConv)
  66. RegCloseKey(g_hkeyGrpConv);
  67. }
  68. // Do this here instead of in Explorer so we don't keep overwriting
  69. // user settings.
  70. #if 1
  71. //----------------------------------------------------------------------------
  72. const TCHAR c_szExplorer[] = TEXT("Explorer");
  73. const TCHAR c_szRestrictions[] = TEXT("Restrictions");
  74. const TCHAR c_szEditLevel[] = TEXT("EditLevel");
  75. const TCHAR c_szNoRun[] = TEXT("NoRun");
  76. const TCHAR c_szNoClose[] = TEXT("NoClose");
  77. const TCHAR c_szNoSaveSettings[] = TEXT("NoSaveSettings");
  78. const TCHAR c_szNoFileMenu[] = TEXT("NoFileMenu");
  79. const TCHAR c_szShowCommonGroups[] = TEXT("ShowCommonGroups");
  80. const TCHAR c_szNoCommonGroups[] = TEXT("NoCommonGroups");
  81. void Restrictions_Convert(LPCTSTR szIniFile)
  82. {
  83. DWORD dw, cbData, dwType;
  84. HKEY hkeyPolicies, hkeyPMRestrict;
  85. DebugMsg(DM_TRACE, TEXT("c.cr: Converting restrictions..."));
  86. if (RegCreateKey(HKEY_CURRENT_USER, REGSTR_PATH_POLICIES, &hkeyPolicies) == ERROR_SUCCESS)
  87. {
  88. // Get them. Set them.
  89. if (RegOpenKeyEx(HKEY_CURRENT_USER,
  90. TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Program Manager\\Restrictions"),
  91. 0, KEY_READ, &hkeyPMRestrict) == ERROR_SUCCESS) {
  92. cbData = sizeof(dw);
  93. dw = 0;
  94. RegQueryValueEx(hkeyPMRestrict, c_szEditLevel, 0, &dwType, (LPBYTE)&dw, &cbData);
  95. Reg_SetDWord(hkeyPolicies, c_szExplorer, c_szEditLevel, dw);
  96. dw = 0;
  97. RegQueryValueEx(hkeyPMRestrict, c_szNoRun, 0, &dwType, (LPBYTE)&dw, &cbData);
  98. Reg_SetDWord(hkeyPolicies, c_szExplorer, c_szNoRun, dw);
  99. dw = 0;
  100. RegQueryValueEx(hkeyPMRestrict, c_szNoClose, 0, &dwType, (LPBYTE)&dw, &cbData);
  101. Reg_SetDWord(hkeyPolicies, c_szExplorer, c_szNoClose, dw);
  102. dw = 0;
  103. RegQueryValueEx(hkeyPMRestrict, c_szNoSaveSettings, 0, &dwType, (LPBYTE)&dw, &cbData);
  104. Reg_SetDWord(hkeyPolicies, c_szExplorer, c_szNoSaveSettings, dw);
  105. dw = 0;
  106. RegQueryValueEx(hkeyPMRestrict, c_szNoFileMenu, 0, &dwType, (LPBYTE)&dw, &cbData);
  107. Reg_SetDWord(hkeyPolicies, c_szExplorer, c_szNoFileMenu, dw);
  108. dw = 0;
  109. if (RegQueryValueEx(hkeyPMRestrict, c_szShowCommonGroups, 0, &dwType, (LPBYTE)&dw, &cbData) == ERROR_SUCCESS) {
  110. dw = !dw;
  111. }
  112. Reg_SetDWord(hkeyPolicies, c_szExplorer, c_szNoCommonGroups, dw);
  113. RegCloseKey (hkeyPMRestrict);
  114. }
  115. RegCloseKey(hkeyPolicies);
  116. }
  117. else
  118. {
  119. DebugMsg(DM_ERROR, TEXT("gc.cr: Unable to create policy key for registry."));
  120. DebugMsg(DM_ERROR, TEXT("gc.cr: Restrictions can not be converted."));
  121. }
  122. }
  123. #endif
  124. void CALLBACK Group_EnumCallback(LPCTSTR lpszGroup)
  125. {
  126. Group_Convert(NULL, lpszGroup, 0);
  127. }
  128. // convert all 3.x groups to chicago directories and links
  129. void DoAutoConvert(BOOL fModifiedOnly, BOOL bConvertGRPFiles)
  130. {
  131. TCHAR szIniFile[MAX_PATH];
  132. int cb, cGroups = 0;
  133. Restrictions_Convert(NULL);
  134. cGroups = Group_EnumNT(Group_EnumCallback, TRUE, fModifiedOnly,
  135. HKEY_CURRENT_USER, c_szUnicodeGroups);
  136. if (cGroups == 0) {
  137. //
  138. // Try ANSI progman groups (Upgrade from NT 3.1)
  139. //
  140. cGroups = Group_EnumNT(Group_EnumCallback, TRUE, fModifiedOnly,
  141. HKEY_CURRENT_USER, c_szAnsiGroups);
  142. }
  143. if (bConvertGRPFiles && (cGroups == 0)) {
  144. //
  145. // Convert .grp files
  146. //
  147. cGroups = Group_Enum(Group_EnumCallback, TRUE, fModifiedOnly);
  148. }
  149. }
  150. void CALLBACK Group_ListApps(LPCTSTR lpszGroup)
  151. {
  152. DebugMsg(DM_TRACE, TEXT("gc.g_la: %s"), lpszGroup);
  153. Group_Convert(NULL, lpszGroup, GC_BUILDLIST);
  154. }
  155. // Grovel the old .grp files to build a list of all the old installed apps.
  156. void AppList_Build(void)
  157. {
  158. DebugMsg(DM_TRACE, TEXT("gc.bal: Building app list..."));
  159. AppList_Create();
  160. Group_EnumOldGroups(Group_ListApps, TRUE);
  161. AppList_AddCurrentStuff();
  162. AppList_WriteFile();
  163. AppList_Destroy();
  164. }
  165. // FILE_ATTRIBUTE_READONLY 0x00000001
  166. // FILE_ATTRIBUTE_HIDDEN 0x00000002
  167. // FILE_ATTRIBUTE_SYSTEM 0x00000004
  168. void DoDelete(LPCTSTR pszPath, LPCTSTR pszLongName)
  169. {
  170. TCHAR szTo[MAX_PATH], szTemp[MAX_PATH];
  171. BOOL fDir = FALSE;
  172. // if the first character is an asterisk, it means to
  173. // treat the name as a directory
  174. if (*pszLongName == TEXT('*'))
  175. {
  176. fDir = TRUE;
  177. pszLongName = CharNext(pszLongName);
  178. }
  179. if (ParseField(pszLongName, 1, szTemp, ARRAYSIZE(szTemp)))
  180. {
  181. PathCombine(szTo, pszPath, szTemp);
  182. if (fDir)
  183. {
  184. // NOTE: RemoveDirectory fails if the directory
  185. // is not empty. It is by design that we do not
  186. // recursively delete every file and directory.
  187. RemoveDirectory(szTo);
  188. }
  189. else
  190. {
  191. DeleteFile(szTo);
  192. }
  193. }
  194. }
  195. void DoRenameSetAttrib(LPCTSTR pszPath, LPCTSTR pszShortName, LPCTSTR pszLongName, BOOL bLFN)
  196. {
  197. DWORD dwAttributes;
  198. TCHAR szFrom[MAX_PATH], szTo[MAX_PATH], szTemp[MAX_PATH];
  199. if (bLFN && (ParseField(pszLongName, 1, szTemp, ARRAYSIZE(szTemp))))
  200. {
  201. PathCombine(szFrom, pszPath, pszShortName);
  202. PathCombine(szTo, pszPath, szTemp);
  203. if (!MoveFile(szFrom, szTo))
  204. {
  205. DWORD dwError = GetLastError();
  206. DebugMsg(DM_TRACE, TEXT("c.rsa: Rename %s Failed %x"), szFrom, dwError);
  207. // Does the destination already exist?
  208. if (dwError == ERROR_ALREADY_EXISTS)
  209. {
  210. // Delete it.
  211. if (DeleteFile(szTo))
  212. {
  213. if (!MoveFile(szFrom, szTo))
  214. {
  215. dwError = GetLastError();
  216. DebugMsg(DM_TRACE, TEXT("c.rsa: Rename after Delete %s Failed %x"), szFrom, dwError);
  217. }
  218. }
  219. }
  220. }
  221. }
  222. else
  223. {
  224. // use this to set the attributes on
  225. PathCombine(szTo, pszPath, pszShortName);
  226. }
  227. ParseField(pszLongName, 2, szTemp, ARRAYSIZE(szTemp));
  228. dwAttributes = (DWORD)StrToInt(szTemp);
  229. if (dwAttributes)
  230. SetFileAttributes(szTo, dwAttributes);
  231. }
  232. const TCHAR c_szDeleteRoot[] = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\DeleteFiles");
  233. const TCHAR c_szRenameRoot[] = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\RenameFiles");
  234. const TCHAR c_szPreRenameRoot[] = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\PreConvRenameFiles");
  235. //
  236. // this was stolen from shlwapi\reg.c, we cant link to it since we are "grpconv.exe",
  237. // and we do not move in the same social circles as shlwapi.
  238. //
  239. DWORD NT5RegDeleteKey(HKEY hkey, LPCTSTR pszSubKey)
  240. {
  241. DWORD dwRet;
  242. HKEY hkSubKey;
  243. // Open the subkey so we can enumerate any children
  244. dwRet = RegOpenKeyEx(hkey, pszSubKey, 0, KEY_ALL_ACCESS, &hkSubKey);
  245. if (ERROR_SUCCESS == dwRet)
  246. {
  247. DWORD dwIndex;
  248. TCHAR szSubKeyName[MAX_PATH + 1];
  249. DWORD cchSubKeyName = ARRAYSIZE(szSubKeyName);
  250. TCHAR szClass[MAX_PATH];
  251. DWORD cbClass = ARRAYSIZE(szClass);
  252. // I can't just call RegEnumKey with an ever-increasing index, because
  253. // I'm deleting the subkeys as I go, which alters the indices of the
  254. // remaining subkeys in an implementation-dependent way. In order to
  255. // be safe, I have to count backwards while deleting the subkeys.
  256. // Find out how many subkeys there are
  257. dwRet = RegQueryInfoKey(hkSubKey,
  258. szClass,
  259. &cbClass,
  260. NULL,
  261. &dwIndex, // The # of subkeys -- all we need
  262. NULL,
  263. NULL,
  264. NULL,
  265. NULL,
  266. NULL,
  267. NULL,
  268. NULL);
  269. if (NO_ERROR == dwRet)
  270. {
  271. // dwIndex is now the count of subkeys, but it needs to be
  272. // zero-based for RegEnumKey, so I'll pre-decrement, rather
  273. // than post-decrement.
  274. while (ERROR_SUCCESS == RegEnumKey(hkSubKey, --dwIndex, szSubKeyName, cchSubKeyName))
  275. {
  276. NT5RegDeleteKey(hkSubKey, szSubKeyName);
  277. }
  278. }
  279. RegCloseKey(hkSubKey);
  280. dwRet = RegDeleteKey(hkey, pszSubKey);
  281. }
  282. return dwRet;
  283. }
  284. void DoFileRenamesOrDeletes(LPCTSTR pszKey, BOOL fDelete)
  285. {
  286. HKEY hkey;
  287. if (RegOpenKey(HKEY_LOCAL_MACHINE, pszKey, &hkey) == ERROR_SUCCESS)
  288. {
  289. TCHAR szKey[32];
  290. int iKey;
  291. for (iKey = 0; RegEnumKey(hkey, iKey, szKey, ARRAYSIZE(szKey)) == ERROR_SUCCESS; iKey++)
  292. {
  293. HKEY hkeyEnum;
  294. // each key under here lists files to be renamed in a certain folder
  295. if (RegOpenKey(hkey, szKey, &hkeyEnum) == ERROR_SUCCESS)
  296. {
  297. DWORD cbValue;
  298. TCHAR szPath[MAX_PATH];
  299. // get the path where these files are
  300. cbValue = sizeof(szPath);
  301. if ((RegQueryValue(hkey, szKey, szPath, &cbValue) == ERROR_SUCCESS) && szPath[0])
  302. {
  303. TCHAR szShortName[13], szLongName[MAX_PATH];
  304. DWORD cbData, cbValue, dwType, iValue;
  305. BOOL bLFN = IsLFNDrive(szPath);
  306. for (iValue = 0; cbValue = ARRAYSIZE(szShortName), cbData = sizeof(szLongName),
  307. (RegEnumValue(hkeyEnum, iValue, szShortName, &cbValue, NULL, &dwType, (LPBYTE)szLongName, &cbData) == ERROR_SUCCESS);
  308. iValue++)
  309. {
  310. if (szShortName[0] && ( dwType == REG_SZ ) )
  311. {
  312. if (fDelete)
  313. DoDelete(szPath, szLongName);
  314. else
  315. DoRenameSetAttrib(szPath, szShortName, szLongName, bLFN);
  316. }
  317. }
  318. }
  319. RegCloseKey(hkeyEnum);
  320. }
  321. }
  322. // Toast this whole section so we don't ever try to do renames or deletes twice.
  323. // We need to call NT5RegDeleteKey since on NT we dont nuke it if subkeys exist, but this helper does.
  324. NT5RegDeleteKey(HKEY_LOCAL_MACHINE, pszKey);
  325. RegCloseKey(hkey);
  326. }
  327. }
  328. void DoFileRenames(LPCTSTR pszKey)
  329. {
  330. DoFileRenamesOrDeletes(pszKey, FALSE);
  331. }
  332. void DoFileDeletes(LPCTSTR pszKey)
  333. {
  334. DoFileRenamesOrDeletes(pszKey, TRUE);
  335. }
  336. const TCHAR c_szLinksRoot[] = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Links");
  337. void DoCopyLinks()
  338. {
  339. HKEY hkey;
  340. BOOL bLFN;
  341. LPTSTR szSrcName, szDstName, szGroupFolder, szLinkName, szCmd;
  342. // DebugBreak();
  343. // Allocate buffer
  344. //
  345. if ((szSrcName = (LPTSTR)LocalAlloc(LPTR, 6*MAX_PATH)) == NULL)
  346. return;
  347. szDstName = szSrcName+MAX_PATH;
  348. szGroupFolder = szDstName+MAX_PATH;
  349. szLinkName = szGroupFolder+MAX_PATH;
  350. szCmd = szLinkName+MAX_PATH;
  351. // Get the path to the special folder
  352. //
  353. SHGetSpecialFolderPath(NULL, szGroupFolder, CSIDL_PROGRAMS, TRUE);
  354. bLFN = IsLFNDrive(szGroupFolder);
  355. // Enumerate each link
  356. //
  357. if (RegOpenKey(HKEY_LOCAL_MACHINE, c_szLinksRoot, &hkey) == ERROR_SUCCESS)
  358. {
  359. DWORD cbData, cbValue, dwType, iValue;
  360. for (iValue = 0; cbValue = MAX_PATH, cbData = 2*MAX_PATH*sizeof(TCHAR),
  361. (RegEnumValue(hkey, iValue, szLinkName, &cbValue, NULL, &dwType, (LPBYTE)szCmd, &cbData) == ERROR_SUCCESS);
  362. iValue++)
  363. {
  364. if (szLinkName[0] && (dwType == REG_SZ))
  365. {
  366. // Build the destination name
  367. //
  368. lstrcpy(szDstName, szGroupFolder);
  369. ParseField(szCmd, 1, szSrcName, MAX_PATH);
  370. PathAppend(szDstName, szSrcName);
  371. // Check the volume type
  372. //
  373. if (bLFN)
  374. {
  375. PathAppend(szDstName, szLinkName);
  376. lstrcat(szDstName, TEXT(".lnk"));
  377. ParseField(szCmd, 2, szSrcName, MAX_PATH);
  378. }
  379. else
  380. {
  381. ParseField(szCmd, 2, szSrcName, MAX_PATH);
  382. PathAppend(szDstName, PathFindFileName(szSrcName));
  383. }
  384. MoveFile(szSrcName, szDstName);
  385. }
  386. }
  387. // Nuke this section so we don't do copies twice.
  388. RegDeleteKey(HKEY_LOCAL_MACHINE, c_szLinksRoot);
  389. RegCloseKey(hkey);
  390. }
  391. LocalFree((HLOCAL)szSrcName);
  392. }
  393. // makes sure the current user's metrics are stored in scalable units
  394. void ConvertMetricsToScalableUnits(BOOL fKeepBradsSettings)
  395. {
  396. NONCLIENTMETRICS ncm;
  397. LOGFONT lf;
  398. HDC screen;
  399. int value;
  400. int floor = 0;
  401. // USER always writes out font sizes in points and metrics in twips
  402. // get and set everything of interest
  403. ncm.cbSize = sizeof( NONCLIENTMETRICS );
  404. SystemParametersInfo( SPI_GETNONCLIENTMETRICS, sizeof( ncm ),
  405. (void *)(LPNONCLIENTMETRICS)&ncm, FALSE );
  406. SystemParametersInfo( SPI_SETNONCLIENTMETRICS, sizeof( ncm ),
  407. (void *)(LPNONCLIENTMETRICS)&ncm, SPIF_UPDATEINIFILE );
  408. SystemParametersInfo( SPI_GETICONTITLELOGFONT, sizeof( lf ),
  409. (void *)(LPLOGFONT)&lf, FALSE );
  410. SystemParametersInfo( SPI_SETICONTITLELOGFONT, sizeof( lf ),
  411. (void *)(LPLOGFONT)&lf, SPIF_UPDATEINIFILE );
  412. // HACK: Win3x users could get into 120 DPI without upping the icon spacing
  413. // they need the equivalent of 75 pixels in the current logical resolution
  414. if (!fKeepBradsSettings)
  415. {
  416. screen = GetDC( NULL );
  417. if (screen)
  418. {
  419. floor = MulDiv( 75, GetDeviceCaps( screen, LOGPIXELSX ), 96 );
  420. ReleaseDC( NULL, screen );
  421. }
  422. else
  423. {
  424. floor = 0;
  425. }
  426. value = GetSystemMetrics( SM_CXICONSPACING );
  427. SystemParametersInfo( SPI_ICONHORIZONTALSPACING, max( value, floor ),
  428. NULL, SPIF_UPDATEINIFILE );
  429. value = GetSystemMetrics( SM_CYICONSPACING );
  430. SystemParametersInfo( SPI_ICONVERTICALSPACING, max( value, floor ),
  431. NULL, SPIF_UPDATEINIFILE );
  432. }
  433. }
  434. //----------------------------------------------------------------------------
  435. // We need to nuke progman's window settings on first boot so it doesn't
  436. // fill the screen and obscure the tray if we're in Win3.1 UI mode.
  437. void NukeProgmanSettings(void)
  438. {
  439. WritePrivateProfileString(c_szSettings, c_szWindow, NULL, c_szProgmanIni);
  440. }
  441. // Tells Explorer to check the win.ini extensions section.
  442. void ExplorerCheckAssociations(void)
  443. {
  444. DWORD dw = 1;
  445. Reg_Set(HKEY_CURRENT_USER, c_szRegExplorer, c_szCheckAssociations,
  446. REG_BINARY, &dw, sizeof(dw));
  447. }
  448. // The setup flag is set for first boot stuff (-s) and not for maintenance
  449. // mode (-o).
  450. void DoRandomOtherStuff(BOOL fSetup, BOOL fKeepBradsSettings)
  451. {
  452. Log(TEXT("dros: ..."));
  453. Log(TEXT("dros: Renames."));
  454. DoFileRenames(c_szRenameRoot);
  455. Log(TEXT("dros: Copies."));
  456. DoCopyLinks();
  457. Log(TEXT("dros: Deletes."));
  458. DoFileDeletes(c_szDeleteRoot);
  459. if (fSetup)
  460. {
  461. Log(TEXT("dros: Converting metrics."));
  462. ConvertMetricsToScalableUnits(fKeepBradsSettings);
  463. Log(TEXT("dros: Nuking Progman settings."));
  464. NukeProgmanSettings();
  465. // GenerateSetupExitEvent();
  466. ExplorerCheckAssociations();
  467. }
  468. Log(TEXT("dros: Done."));
  469. }
  470. void DoConversion(HINSTANCE hinst, LPTSTR lpszCmdLine)
  471. {
  472. HKEY hKey;
  473. DWORD Err, DataType, DataSize = sizeof(DWORD);
  474. DWORD Value;
  475. TCHAR szFile[MAX_PATH];
  476. TCHAR szFilters[CCHSZNORMAL];
  477. TCHAR szTitle[CCHSZNORMAL];
  478. HCURSOR hCursor;
  479. UINT olderrormode;
  480. *szFile = TEXT('\0');
  481. GetWindowsDirectory(szFile, ARRAYSIZE(szFile));
  482. PathAddBackslash(szFile);
  483. // set the error mode to ignore noopenfileerrorbox so on japanese PC-98 machines
  484. // whose hard drive is A: we dont ask for a floppy when running grpconv.
  485. olderrormode = SetErrorMode(0);
  486. SetErrorMode(olderrormode | SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
  487. // Is GUI Setup currently running?
  488. if ((Err = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  489. TEXT("System\\Setup"),
  490. 0,
  491. KEY_READ,
  492. &hKey)) == ERROR_SUCCESS) {
  493. Err = RegQueryValueEx(
  494. hKey,
  495. TEXT("SystemSetupInProgress"),
  496. NULL,
  497. &DataType,
  498. (LPBYTE)&Value,
  499. &DataSize);
  500. RegCloseKey(hKey);
  501. }
  502. if ( (Err == NO_ERROR) && Value ) {
  503. g_fShowUI = FALSE;
  504. }
  505. if (!lstrcmpi(lpszCmdLine, TEXT("/m")) || !lstrcmpi(lpszCmdLine, TEXT("-m")))
  506. {
  507. // manual mode
  508. // Get something from a commdlg....
  509. LoadString(hinst, IDS_FILTER, szFilters, ARRAYSIZE(szFilters));
  510. ConvertHashesToNulls(szFilters);
  511. LoadString(hinst, IDS_COMMDLGTITLE, szTitle, ARRAYSIZE(szTitle));
  512. // Keep going till they hit cancel.
  513. while (GetFileNameFromBrowse(NULL, szFile, ARRAYSIZE(szFile), NULL, g_szGRP, szFilters, szTitle))
  514. {
  515. Group_CreateProgressDlg();
  516. Group_Convert(NULL, szFile, GC_PROMPTBEFORECONVERT | GC_REPORTERROR | GC_OPENGROUP);
  517. Group_DestroyProgressDlg();
  518. }
  519. }
  520. else if (!lstrcmpi(lpszCmdLine, TEXT("/s")) || !lstrcmpi(lpszCmdLine, TEXT("-s")))
  521. {
  522. // Rebuild - without the logo.
  523. hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  524. DoFileRenames(c_szPreRenameRoot);
  525. DoAutoConvert(FALSE, TRUE);
  526. BuildDefaultGroups();
  527. DoRandomOtherStuff(TRUE, FALSE);
  528. SetCursor(hCursor);
  529. }
  530. else if (!lstrcmpi(lpszCmdLine, TEXT("/n")) || !lstrcmpi(lpszCmdLine, TEXT("-n")))
  531. {
  532. //
  533. // Used by NT setup
  534. //
  535. // 1) Converts ProgMan common groups
  536. //
  537. g_fDoingCommonGroups = TRUE;
  538. Group_EnumNT(Group_EnumCallback, FALSE, FALSE,
  539. HKEY_LOCAL_MACHINE, c_szCommonGroups);
  540. }
  541. else if (!lstrcmpi(lpszCmdLine, TEXT("/c")) || !lstrcmpi(lpszCmdLine, TEXT("-c")))
  542. {
  543. // Convert NT common progman groups only
  544. hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  545. g_fDoingCommonGroups = TRUE;
  546. Group_EnumNT(Group_EnumCallback, TRUE, FALSE,
  547. HKEY_LOCAL_MACHINE, c_szCommonGroups);
  548. SetCursor(hCursor);
  549. }
  550. else if (!lstrcmpi(lpszCmdLine, TEXT("/p")) || !lstrcmpi(lpszCmdLine, TEXT("-p")))
  551. {
  552. // Convert NT personal progman groups only
  553. // This switch is used by NT setup via userdiff
  554. hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  555. DoAutoConvert(FALSE, FALSE);
  556. SetCursor(hCursor);
  557. }
  558. else if (!lstrcmpi(lpszCmdLine, TEXT("/t")) || !lstrcmpi(lpszCmdLine, TEXT("-t")))
  559. {
  560. // Same as -s but only coverts modified groups (used on a re-install).
  561. hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  562. DoFileRenames(c_szPreRenameRoot);
  563. DoAutoConvert(TRUE, TRUE);
  564. BuildDefaultGroups();
  565. DoRandomOtherStuff(TRUE, TRUE);
  566. SetCursor(hCursor);
  567. }
  568. else if (!lstrcmpi(lpszCmdLine, TEXT("/q")) || !lstrcmpi(lpszCmdLine, TEXT("-q")))
  569. {
  570. // Question and answer stuff.
  571. AppList_Build();
  572. // Restart the reporter tool.
  573. WinExec(c_szReporter, SW_NORMAL);
  574. }
  575. else if (!lstrcmpi(lpszCmdLine, TEXT("/o")) || !lstrcmpi(lpszCmdLine, TEXT("-o")))
  576. {
  577. // Optional component GrpConv (ie don't look at Progman groups).
  578. hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  579. DoFileRenames(c_szPreRenameRoot);
  580. BuildDefaultGroups();
  581. DoRandomOtherStuff(FALSE, FALSE);
  582. SetCursor(hCursor);
  583. }
  584. else if (!lstrcmpi(lpszCmdLine, TEXT("/u")) || !lstrcmpi(lpszCmdLine, TEXT("-u")))
  585. {
  586. // Display NO UI (ie no progress dialog) and process
  587. // Optional components (ie don't look at Progman groups),
  588. g_fShowUI = FALSE;
  589. hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  590. DoFileRenames(c_szPreRenameRoot);
  591. BuildDefaultGroups();
  592. DoRandomOtherStuff(FALSE, FALSE);
  593. SetCursor(hCursor);
  594. }
  595. else if (*lpszCmdLine)
  596. {
  597. // file specified, convert just it
  598. Group_CreateProgressDlg();
  599. Group_Convert(NULL, lpszCmdLine, GC_REPORTERROR | GC_OPENGROUP); // REVIEW, maybe silent?
  600. Group_DestroyProgressDlg();
  601. }
  602. else
  603. {
  604. hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  605. DoFileRenames(c_szPreRenameRoot);
  606. DoAutoConvert(TRUE, TRUE);
  607. DoRandomOtherStuff(FALSE, FALSE);
  608. SetCursor(hCursor);
  609. }
  610. }
  611. // stolen from the CRT, used to shirink our code
  612. int _stdcall ModuleEntry(void)
  613. {
  614. int i;
  615. STARTUPINFO si;
  616. LPTSTR pszCmdLine = GetCommandLine();
  617. if ( *pszCmdLine == TEXT('\"') ) {
  618. /*
  619. * Scan, and skip over, subsequent characters until
  620. * another double-quote or a null is encountered.
  621. */
  622. while ( *++pszCmdLine && (*pszCmdLine
  623. != TEXT('\"')) );
  624. /*
  625. * If we stopped on a double-quote (usual case), skip
  626. * over it.
  627. */
  628. if ( *pszCmdLine == TEXT('\"') )
  629. pszCmdLine++;
  630. }
  631. else {
  632. while (*pszCmdLine > TEXT(' '))
  633. pszCmdLine++;
  634. }
  635. /*
  636. * Skip past any white space preceeding the second token.
  637. */
  638. while (*pszCmdLine && (*pszCmdLine <= TEXT(' '))) {
  639. pszCmdLine++;
  640. }
  641. si.dwFlags = 0;
  642. GetStartupInfo(&si);
  643. i = WinMainT(GetModuleHandle(NULL), NULL, pszCmdLine,
  644. si.dwFlags & STARTF_USESHOWWINDOW ? si.wShowWindow : SW_SHOWDEFAULT);
  645. ExitProcess(i);
  646. return i; // We never comes here.
  647. }
  648. //---------------------------------------------------------------------------
  649. int WinMainT(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
  650. {
  651. LCID lcid;
  652. HMODULE hLibImm;
  653. BOOL (WINAPI *ImmDisableIME)(DWORD) = NULL;
  654. lcid = GetThreadLocale();
  655. // we have to LoadLibaray/GetProcAddress ImmDisableIME because
  656. // this is not exported on win95 gold or NT4.
  657. hLibImm = LoadLibrary(TEXT("imm.dll"));
  658. if (hLibImm)
  659. {
  660. (FARPROC) *ImmDisableIME = GetProcAddress(hLibImm, "ImmDisableIME");
  661. if (ImmDisableIME != NULL)
  662. {
  663. if ( (PRIMARYLANGID(LANGIDFROMLCID(lcid)) == LANG_JAPANESE) ||
  664. (PRIMARYLANGID(LANGIDFROMLCID(lcid)) == LANG_KOREAN) ||
  665. (PRIMARYLANGID(LANGIDFROMLCID(lcid)) == LANG_CHINESE) )
  666. {
  667. ImmDisableIME(0);
  668. }
  669. }
  670. FreeLibrary(hLibImm);
  671. }
  672. g_hinst = hInstance;
  673. if (InitApplication(hInstance))
  674. {
  675. // We do all the work on InitInst
  676. InitCommonControls();
  677. DoConversion(hInstance, lpCmdLine);
  678. UnInitApplication();
  679. }
  680. return TRUE;
  681. }