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.

599 lines
18 KiB

  1. //=--------------------------------------------------------------------------=
  2. // (C) Copyright 1997-1998 Microsoft Corporation. All Rights Reserved.
  3. // TriEdit SDK team
  4. // Author: Yury Polyakovsky
  5. // contact: [email protected]
  6. //=--------------------------------------------------------------------------=
  7. // Refcount support for DLLs
  8. // Call: refcount < Install | Uninstall | CopyToClient | SetClient | ClearClient | Copy >, <registry key> [, <file name>[, <client subdirectory> I <destination for Copy>] | <component full path>]
  9. // Call refcount.exe from an application's setup:
  10. // Install : Increment ref-count for the component if it was not installed before by the app
  11. // Uninstall : Decrement ref-count for the component if it was installed before by the app, deletes it if ref-count goes to 0
  12. // CopyToClient : Copies the component to the application's directory (from the registry)
  13. // SetClient : Set the flag in the registry that the component was installed by the application
  14. // CreateDir : Checks on the directory "C:\Program Files\Common Files" and create one if it's not there
  15. // ClearClient : Clear the flag in the registry that the component was installed by the application
  16. // Copy: Copy to specified destination.
  17. #include <ctype.h>
  18. #include <windef.h>
  19. #include <stdarg.h>
  20. #include <stdlib.h>
  21. #include <winbase.h>
  22. #include <winreg.h>
  23. #include <winuser.h>
  24. #include <crtdbg.h>
  25. #include <shlwapi.h>
  26. #include "RefCount.h"
  27. #define STRINGOP(func, param1, param2) (func(param1, param2, sizeof(param1)/sizeof(param1[0])))
  28. #define STRINGOPL(func, param1, param2) (func(param1, param2, strlen(param1)))
  29. #define SKIPSPACES(psz) {for (++psz; *psz == ' ' && *psz != '\0'; ++psz); if (!*psz) psz=NULL;}
  30. BOOL PASCAL ReplaceFileOnReboot (LPCTSTR pszExisting, LPCTSTR pszNew);
  31. int WINAPI WinMain( HINSTANCE hInstance, // handle to current instance
  32. HINSTANCE hPrevInstance, // handle to previous instance
  33. LPSTR lpCmdLine, // pointer to command line
  34. int nCmdShow) // show state of window);int main(int argc, char** argv)
  35. {
  36. _ASSERT(*lpCmdLine);
  37. if (!*lpCmdLine)
  38. {
  39. // No command line
  40. return 1;
  41. }
  42. CRefCount RefCount;
  43. char szRegKey[MAX_PATH] = "";
  44. char szRegInstalling[MAX_PATH] = "";
  45. char szRegInstalled[MAX_PATH] = "";
  46. char sz_AppPath[MAX_PATH] = "";
  47. char sz_Application[MAX_PATH] = "";
  48. char sz_Dir[MAX_PATH] = "";
  49. char *pszAppPath = sz_AppPath;
  50. char *pszApplication = sz_Application;
  51. BOOL bMultiInstall = FALSE;
  52. BOOL *pbInstallMode = &bMultiInstall;
  53. DWORD dwValueSize = sizeof(sz_AppPath);
  54. //_ASSERT(FALSE);
  55. if (!STRINGOPL(_strnicmp, "CreateDir", lpCmdLine/*argv[1]*/))
  56. {
  57. dwValueSize = sizeof(sz_Application);
  58. RefCount.ValueGet("SOFTWARE\\Microsoft\\Windows\\CurrentVersion", "CommonFilesDir", (LPBYTE *)&pszApplication, &dwValueSize);
  59. _ASSERT(pszApplication);
  60. if (pszApplication)
  61. {
  62. if (!CreateDirectory(pszApplication, NULL))
  63. DWORD dwError = GetLastError();
  64. }
  65. return 0;
  66. }
  67. LPSTR pszRegName = strchr(lpCmdLine, ',');
  68. _ASSERT(pszRegName);
  69. if (!pszRegName)
  70. // command line not complete
  71. return 1;
  72. SKIPSPACES(pszRegName);
  73. _ASSERT(pszRegName);
  74. if (!pszRegName)
  75. // command line not complete
  76. return 1;
  77. LPSTR pszPathName = strchr(pszRegName, ',');
  78. if (pszPathName)
  79. {
  80. SKIPSPACES(pszPathName);
  81. }
  82. STRINGOP(strncpy, szRegKey, pszRegName/*argv[2]*/);
  83. if (LPSTR pszEndRegName = strchr(szRegKey, ','))
  84. *pszEndRegName = '\0';
  85. STRINGOP(strncpy, szRegInstalling, szRegKey/*argv[2]*/);
  86. STRINGOP(strncat , szRegInstalling, "\\InstallingClient");
  87. RefCount.ValueGet(szRegInstalling, "Path", (LPBYTE *)&pszAppPath, &dwValueSize);
  88. dwValueSize = sizeof(sz_Application);
  89. RefCount.ValueGet(szRegInstalling, "Application", (LPBYTE *)&pszApplication, &dwValueSize);
  90. dwValueSize = sizeof(BOOL);
  91. RefCount.ValueGet(szRegInstalling, "MultiInstall", (LPBYTE *)&pbInstallMode, &dwValueSize);
  92. if (pszAppPath && ((pbInstallMode && bMultiInstall) || !STRINGOPL(_strnicmp, "CopyToClient", lpCmdLine/*argv[1]*/)))
  93. {
  94. STRINGOP(strncat, pszAppPath, "\\");
  95. STRINGOP(strncpy, sz_Dir, pszAppPath);
  96. STRINGOP(strncat, sz_AppPath, sz_Application);
  97. }
  98. else
  99. STRINGOP(strncpy, sz_AppPath, sz_Application);
  100. // FInd the path in InstalledClients
  101. STRINGOP(strncpy, szRegInstalled, szRegKey/*argv[2]*/);
  102. STRINGOP(strncat, szRegInstalled, "\\InstalledClients");
  103. char szTmp[MAX_PATH];
  104. strcpy(szTmp, pszPathName);
  105. char* x = strchr(szTmp, ',');
  106. char szGUID[MAX_PATH];
  107. char* pszGUID = NULL;
  108. if( x )
  109. {
  110. // IE passed component guid so we need to check...
  111. strcpy(szGUID, x);
  112. *x = '\0';
  113. strcpy(pszPathName, szTmp);
  114. // now szGuid = " , {aab-cc-dd-ee}", need to stript white space and ','
  115. pszGUID = szGUID;
  116. for( int i = 0; i < MAX_PATH; i++)
  117. {
  118. if( *pszGUID != ' ' && *pszGUID != ',')
  119. break;
  120. pszGUID++;
  121. }
  122. if( i == MAX_PATH || *pszGUID == '\0' )
  123. {
  124. pszGUID = NULL;
  125. }
  126. }
  127. if (!STRINGOPL(_strnicmp, "CopyToClient", lpCmdLine/*argv[1]*/))
  128. {
  129. _ASSERT(pszPathName);
  130. if (!pszPathName)
  131. return 2;
  132. else
  133. {
  134. LPSTR pszDestSubDir = strchr(pszPathName, ',');
  135. if (pszDestSubDir)
  136. {
  137. SKIPSPACES(pszDestSubDir);
  138. STRINGOP(strncat, sz_Dir, pszDestSubDir);
  139. STRINGOP(strncat, sz_Dir, "\\");
  140. }
  141. if (LPSTR pszPathNameEnd = strchr(pszPathName, ','))
  142. *pszPathNameEnd = '\0';
  143. // Copy files we need for Uninstall to the client location
  144. STRINGOP(strncat, sz_Dir, pszPathName);
  145. if (LPSTR pszDestDirEnd = strchr(sz_Dir, ','))
  146. *pszDestDirEnd = '\0';
  147. if (!CopyFile(pszPathName/*argv[3]*/, sz_Dir, FALSE))
  148. {
  149. DWORD dwError = GetLastError();
  150. _ASSERTE(!dwError);
  151. return 2;
  152. }
  153. return 0;
  154. }
  155. }
  156. else if (!STRINGOPL(_strnicmp, "Copy", lpCmdLine/*argv[1]*/))
  157. {
  158. _ASSERT(pszPathName);
  159. if (!pszPathName)
  160. return 2;
  161. else
  162. {
  163. LPSTR pszDestSubDir = strchr(pszPathName, ',');
  164. if (pszDestSubDir)
  165. {
  166. SKIPSPACES(pszDestSubDir);
  167. STRINGOP(strncpy, sz_Dir, pszDestSubDir);
  168. }
  169. if (LPSTR pszPathNameEnd = strchr(pszPathName, ','))
  170. *pszPathNameEnd = '\0';
  171. // Copy files we need for Uninstall to the client location
  172. if (LPSTR pszDestDirEnd = strchr(sz_Dir, ','))
  173. *pszDestDirEnd = '\0';
  174. if (!CopyFile(pszPathName/*argv[3]*/, sz_Dir, FALSE))
  175. {
  176. DWORD dwError = GetLastError();
  177. _ASSERTE(!dwError);
  178. return 2;
  179. }
  180. return 0;
  181. }
  182. }
  183. else if (!RefCount.ValueExist(szRegInstalled, sz_AppPath) && !STRINGOPL(_strnicmp, "Install", lpCmdLine/*argv[1]*/))
  184. {
  185. // Increment ref-count
  186. if( pszGUID )
  187. {
  188. // some check needed...
  189. // is the component installed?
  190. HKEY hkInstalled = NULL;
  191. char szKeyName[MAX_PATH];
  192. strcpy(szKeyName, "SOFTWARE\\Microsoft\\Active Setup\\Installed Components\\");
  193. strcat(szKeyName, pszGUID);
  194. if( ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_ALL_ACCESS, &hkInstalled)
  195. )
  196. {
  197. DWORD dwType = 0;
  198. BYTE bValueData[16];
  199. DWORD cValueData = sizeof(bValueData);;
  200. if (ERROR_SUCCESS == RegQueryValueEx( hkInstalled, "IsInstalled", NULL, &dwType, bValueData, &cValueData))
  201. {
  202. if( *(LPDWORD)(bValueData) )
  203. {
  204. // this app has been installed, we need to do nothing... (do not perform refcount, just quit)
  205. RegCloseKey(hkInstalled);
  206. return 0;
  207. }
  208. }
  209. RegCloseKey(hkInstalled);
  210. }
  211. }
  212. // we are here because
  213. // 1. no guid passed from cmd line
  214. // 2. or component not installed (the RegQueryValue failed..)
  215. // so we continue to do refcount...
  216. RefCount.SetInstalFlag(TRUE);
  217. }
  218. else if (!RefCount.ValueExist(szRegInstalled, sz_AppPath) && !STRINGOPL(_strnicmp, "SetClient", lpCmdLine/*argv[1]*/))
  219. {
  220. // Set the app's installed flag
  221. RefCount.ValueSet(szRegInstalled, sz_AppPath);
  222. RegDeleteKey (HKEY_LOCAL_MACHINE, szRegInstalling); // we don't need it anymore
  223. return 0;
  224. }
  225. else if (!STRINGOPL(_strnicmp, "Uninstall", lpCmdLine/*argv[1]*/))
  226. {
  227. // Decrement ref-count
  228. RefCount.SetInstalFlag(FALSE);
  229. }
  230. else if (!STRINGOPL(_strnicmp, "ClearClient", lpCmdLine/*argv[1]*/))
  231. {
  232. // Remove the app's installed flag
  233. RefCount.ValueClear(szRegInstalled, sz_AppPath);
  234. RegDeleteKey(HKEY_LOCAL_MACHINE, szRegInstalling); // we don't need it anymore
  235. return 0;
  236. }
  237. else if (!STRINGOPL(_strnicmp, "SetClient", lpCmdLine/*argv[1]*/))
  238. {
  239. // Subsequent Installation
  240. RegDeleteKey(HKEY_LOCAL_MACHINE, szRegInstalling); // we don't need it anymore
  241. return 0;
  242. }
  243. else
  244. // Subsequent Installation
  245. return 0;
  246. HKEY hkRef; // address of handle to open key
  247. DWORD dwDisposition; // address of disposition value buffer
  248. LONG lRet;
  249. lRet = RegCreateKeyEx (HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\SharedDLLs",
  250. 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkRef, &dwDisposition);
  251. _ASSERT(REG_OPENED_EXISTING_KEY == dwDisposition);
  252. _ASSERT(ERROR_SUCCESS == lRet);
  253. if (ERROR_SUCCESS != lRet)
  254. {
  255. return 3;
  256. }
  257. _ASSERT(pszPathName);
  258. if (pszPathName)
  259. {
  260. RefCount.Change(pszPathName/*argv[3]*/, &hkRef);
  261. if (RefCount.GetCount() <= 0)
  262. {
  263. _ASSERT(RefCount.GetCount() == 0);
  264. //RegDeleteKey(HKEY_LOCAL_MACHINE, szRegInstalling); // we don't need it anymore
  265. //RegDeleteKey(HKEY_LOCAL_MACHINE, szRegInstalled); // we don't need it anymore
  266. //RegDeleteKey(HKEY_LOCAL_MACHINE, szRegKey); // we don't need it anymore
  267. }
  268. }
  269. RegCloseKey(hkRef);
  270. return 0;
  271. }
  272. void CRefCount::Change(char *szName, PHKEY phkRef)
  273. {
  274. DWORD dwIndex = 0;
  275. DWORD cValueName = 0;
  276. DWORD dwType = 0;
  277. BYTE bValueData[16];
  278. DWORD cValueData = sizeof(bValueData);;
  279. // Check if the conponent exits
  280. if (ERROR_SUCCESS == RegQueryValueEx( *phkRef, szName, NULL, &dwType, bValueData, &cValueData))
  281. {
  282. // Found
  283. _ASSERT(dwType == REG_DWORD);
  284. m_dwRefCount = *(LPDWORD)(bValueData);
  285. (m_fInstall) ? ++m_dwRefCount : --m_dwRefCount;
  286. }
  287. else if (!m_fInstall)
  288. {
  289. // Trying to Uninstall the component that was not ref-counted before
  290. // Just delete it
  291. // _ASSERT(m_fInstall);
  292. if (!DeleteFile(szName))
  293. {
  294. if (!ReplaceFileOnReboot(szName, NULL))
  295. {
  296. DWORD dwError = GetLastError();
  297. _ASSERTE(!dwError);
  298. }
  299. }
  300. return;
  301. }
  302. // If not found, create new else just overwrite it.
  303. *(LPDWORD)(bValueData) = m_dwRefCount;
  304. if (m_dwRefCount == 0)
  305. {
  306. char szDllFullPath[MAX_PATH+1];
  307. DWORD dwLen = 0;
  308. dwLen = strlen(szName);
  309. char* p = NULL;
  310. if( dwLen <= MAX_PATH )
  311. {
  312. strcpy(szDllFullPath, szName);
  313. for( int i = dwLen; i >= 0; i--)
  314. {
  315. if( szDllFullPath[i] == '\\' )
  316. {
  317. p = &(szDllFullPath[i+1]);
  318. break;
  319. }
  320. }
  321. }
  322. if( p &&
  323. !_stricmp(p, "msdapml.dll") &&
  324. !_stricmp(p, "msonsext.dll") &&
  325. !_stricmp(p, "ragent.tlb") &&
  326. !_stricmp(p, "ragent.dll") &&
  327. !_stricmp(p, "fp4autl.dll") &&
  328. !_stricmp(p, "fp4anwi.dll")
  329. ) {
  330. // Last rererence deleted
  331. HINSTANCE hInst = LoadLibrary(szName);
  332. FARPROC pDllUnregisterServer = NULL;
  333. if (hInst && (pDllUnregisterServer = GetProcAddress(hInst, "DllUnregisterServer")))
  334. {
  335. pDllUnregisterServer();
  336. }
  337. else
  338. {
  339. DWORD dwError = GetLastError();
  340. }
  341. FreeLibrary(hInst);
  342. }
  343. RegDeleteValue(*phkRef, szName);
  344. if (!DeleteFile(szName))
  345. {
  346. if (!ReplaceFileOnReboot(szName, NULL))
  347. {
  348. DWORD dwError = GetLastError();
  349. _ASSERTE(!dwError);
  350. }
  351. }
  352. if( p && !_stricmp(p, "msonsext.dll") )
  353. {
  354. LONG lRet =0;
  355. lRet = RegDeleteKey (HKEY_CLASSES_ROOT,"CLSID\\{BDEADF00-C265-11d0-BCED-00A0C90AB50F}");
  356. lRet = RegDeleteKey (HKEY_CLASSES_ROOT,"CLSID\\{BDEADF04-C265-11d0-BCED-00A0C90AB50F}");
  357. lRet = RegDeleteKey (HKEY_CLASSES_ROOT,"Publishing Folder");
  358. lRet = RegDeleteKey (HKEY_LOCAL_MACHINE,"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MyComputer\\NameSpace\\{BDEADF00-C265-11d0-BCED-00A0C90AB50F}");
  359. HKEY hkRef = NULL;
  360. lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE,"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved", 0, KEY_ALL_ACCESS, &hkRef);
  361. if (ERROR_SUCCESS == lRet)
  362. {
  363. RegDeleteValue(hkRef, "{BDEADF00-C265-11d0-BCED-00A0C90AB50F}");
  364. RegCloseKey(hkRef);
  365. }
  366. }
  367. }
  368. else
  369. RegSetValueEx(*phkRef, szName, 0, REG_DWORD, bValueData, sizeof(DWORD));
  370. }
  371. BOOL CRefCount::ValueExist(char *sz_RegSubkey, char *sz_RegValue)
  372. {
  373. HKEY hkRef = NULL; // address of handle to open key
  374. LONG lRet =0;
  375. BOOL fret = FALSE;
  376. lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, sz_RegSubkey,
  377. 0, KEY_ALL_ACCESS, &hkRef);
  378. if (ERROR_SUCCESS != lRet)
  379. {
  380. return FALSE;
  381. }
  382. else
  383. {
  384. lRet = RegQueryValueEx(hkRef, sz_RegValue, 0, NULL, NULL, NULL);
  385. if (ERROR_SUCCESS != lRet)
  386. fret = FALSE;
  387. else
  388. fret = TRUE;
  389. }
  390. RegCloseKey(hkRef);
  391. return fret;
  392. }
  393. void CRefCount::ValueSet(char *sz_RegSubkey, char *sz_RegValue)
  394. {
  395. HKEY hkRef = NULL; // address of handle to open key
  396. LONG lRet =0;
  397. DWORD dwValiue = 1;
  398. DWORD dwDisposition; // address of disposition value buffer
  399. lRet = RegCreateKeyEx(HKEY_LOCAL_MACHINE, sz_RegSubkey,
  400. 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkRef, &dwDisposition);
  401. _ASSERT(ERROR_SUCCESS == lRet);
  402. if (ERROR_SUCCESS != lRet)
  403. {
  404. return;
  405. }
  406. else
  407. {
  408. RegSetValueEx(hkRef, sz_RegValue, 0, REG_DWORD, (BYTE *)&dwValiue, sizeof(dwValiue));
  409. }
  410. }
  411. void CRefCount::ValueGet(char *sz_RegSubkey, char *sz_ValueName, LPBYTE *p_Value, DWORD *pdwValueSize)
  412. {
  413. HKEY hkRef = NULL; // address of handle to open key
  414. LONG lRet =0;
  415. DWORD dwValiue = 1;
  416. lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, sz_RegSubkey,
  417. 0, KEY_ALL_ACCESS, &hkRef);
  418. if (ERROR_SUCCESS != lRet)
  419. {
  420. *p_Value = NULL;
  421. }
  422. else
  423. {
  424. lRet = RegQueryValueEx(hkRef, sz_ValueName, 0, NULL, *p_Value, pdwValueSize);
  425. if (ERROR_SUCCESS != lRet)
  426. {
  427. *p_Value = NULL;
  428. }
  429. }
  430. }
  431. void CRefCount::ValueClear(char *sz_RegSubkey, char *sz_RegValue)
  432. {
  433. HKEY hkRef = NULL; // address of handle to open key
  434. LONG lRet =0;
  435. DWORD dwValiue = 1;
  436. lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, sz_RegSubkey,
  437. 0, KEY_ALL_ACCESS, &hkRef);
  438. if (ERROR_SUCCESS != lRet)
  439. {
  440. return;
  441. }
  442. else
  443. {
  444. RegDeleteValue(hkRef, sz_RegValue);
  445. }
  446. }
  447. BOOL PASCAL ReplaceFileOnReboot (LPCTSTR pszExisting, LPCTSTR pszNew)
  448. {
  449. // _ASSERT(FALSE);
  450. // First, attempt to use the MoveFileEx function.
  451. BOOL fOk = MoveFileEx(pszExisting, pszNew, MOVEFILE_DELAY_UNTIL_REBOOT);
  452. if (fOk) return(fOk);
  453. // If MoveFileEx failed, we are running on Windows 95 and need to add
  454. // entries to the WININIT.INI file (an ANSI file).
  455. // Start a new scope for local variables.
  456. {
  457. char szRenameLine[1024];
  458. TCHAR szExistingShort[_MAX_PATH];
  459. GetShortPathName(pszExisting, szExistingShort, sizeof(szExistingShort) / sizeof(szExistingShort[0]));
  460. int cchRenameLine = wsprintfA(szRenameLine,
  461. #ifdef UNICODE
  462. "%ls=%ls\r\n",
  463. #else
  464. "%hs=%hs\r\n",
  465. #endif
  466. (pszNew == NULL) ? __TEXT("NUL") : pszNew, szExistingShort);
  467. char szRenameSec[] = "[Rename]\r\n";
  468. int cchRenameSec = sizeof(szRenameSec) - 1;
  469. HANDLE hfile, hfilemap;
  470. DWORD dwFileSize, dwRenameLinePos;
  471. TCHAR szPathnameWinInit[_MAX_PATH];
  472. // Construct the full pathname of the WININIT.INI file.
  473. GetWindowsDirectory(szPathnameWinInit, _MAX_PATH);
  474. lstrcat(szPathnameWinInit, __TEXT("\\WinInit.Ini"));
  475. // Open/Create the WININIT.INI file.
  476. hfile = CreateFile(szPathnameWinInit,
  477. GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS,
  478. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
  479. if (hfile == INVALID_HANDLE_VALUE)
  480. return(fOk); // It is still FALSE
  481. // Create a file mapping object that is the current size of
  482. // the WININIT.INI file plus the length of the additional string
  483. // that we're about to insert into it plus the length of the section
  484. // header (which we might have to add).
  485. dwFileSize = GetFileSize(hfile, NULL);
  486. hfilemap = CreateFileMapping(hfile, NULL, PAGE_READWRITE, 0,
  487. dwFileSize + cchRenameLine + cchRenameSec, NULL);
  488. if (hfilemap != NULL) {
  489. // Map the WININIT.INI file into memory. Note: The contents
  490. // of WININIT.INI are always ANSI; never Unicode.
  491. LPSTR pszWinInit = (LPSTR) MapViewOfFile(hfilemap,
  492. FILE_MAP_WRITE, 0, 0, 0);
  493. pszWinInit[dwFileSize] = 0; // Make sure it is null terminated. Yury
  494. if (pszWinInit != NULL) {
  495. // Search for the [Rename] section in the file.
  496. LPSTR pszRenameSecInFile = strstr(pszWinInit, szRenameSec);
  497. if (pszRenameSecInFile == NULL) {
  498. // There is no [Rename] section in the WININIT.INI file.
  499. // We must add the section too.
  500. dwFileSize += wsprintfA(&pszWinInit[dwFileSize], "%s",
  501. szRenameSec);
  502. dwRenameLinePos = dwFileSize;
  503. } else {
  504. // We found the [Rename] section, shift all the lines down
  505. PSTR pszFirstRenameLine = strchr(pszRenameSecInFile, '\n');
  506. // Shift the contents of the file down to make room for
  507. // the newly added line. The new line is always added
  508. // to the top of the list.
  509. pszFirstRenameLine++; // 1st char on the next line
  510. memmove(pszFirstRenameLine + cchRenameLine, pszFirstRenameLine,
  511. pszWinInit + dwFileSize - pszFirstRenameLine);
  512. dwRenameLinePos = pszFirstRenameLine - pszWinInit;
  513. }
  514. // Insert the new line
  515. memcpy(&pszWinInit[dwRenameLinePos], szRenameLine, cchRenameLine);
  516. UnmapViewOfFile(pszWinInit);
  517. // Calculate the true, new size of the file.
  518. dwFileSize += cchRenameLine;
  519. // Everything was successful.
  520. fOk = TRUE;
  521. }
  522. CloseHandle(hfilemap);
  523. }
  524. // Force the end of the file to be the calculated, new size.
  525. SetFilePointer(hfile, dwFileSize, NULL, FILE_BEGIN);
  526. SetEndOfFile(hfile);
  527. CloseHandle(hfile);
  528. }
  529. return(fOk);
  530. }