init.c
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 36k
Category:

Windows Kernel

Development Platform:

Visual C++

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