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.

589 lines
15 KiB

  1. /*** reginst.c - RegInstall API
  2. *
  3. * This file contains the RegInstall API and its implementation.
  4. *
  5. * Copyright (c) 1996 Microsoft Corporation
  6. * Author: Matt Squires (MattSq)
  7. * Created 08/12/96
  8. */
  9. #include <windows.h>
  10. #include <ole2.h>
  11. #include <advpub.h>
  12. #include <setupapi.h>
  13. #include "globals.h"
  14. #include "advpack.h"
  15. #include "regstr.h"
  16. // FIXFIX - Sundown - let's use public de
  17. // #define IS_RESOURCE(x) ((((LPTSTR)(x)) <= MAKEINTRESOURCE(-1)) && (((LPTSTR)(x)) != NULL))
  18. #define IS_RESOURCE(x) ( (((LPTSTR)(x)) != NULL) && IS_INTRESOURCE(x) )
  19. #define FILESIZE_63K 64449
  20. BOOL GetProgramFilesDir( LPSTR pszPrgfDir, int iSize )
  21. {
  22. *pszPrgfDir = 0;
  23. if ( ctx.wOSVer >= _OSVER_WINNT50 )
  24. {
  25. if ( GetEnvironmentVariable( TEXT("ProgramFiles"), pszPrgfDir, iSize ) )
  26. return TRUE;
  27. }
  28. if ( GetValueFromRegistry( pszPrgfDir, iSize, "HKLM", REGSTR_PATH_SETUP, REGVAL_PROGRAMFILES ) )
  29. {
  30. if ( ctx.wOSVer >= _OSVER_WINNT40 )
  31. {
  32. char szSysDrv[5] = { 0 };
  33. // combine reg value and systemDrive to get the acurate ProgramFiles dir
  34. if ( GetEnvironmentVariable( TEXT("SystemDrive"), szSysDrv, ARRAYSIZE(szSysDrv) ) &&
  35. szSysDrv[0] )
  36. *pszPrgfDir = szSysDrv[0];
  37. }
  38. return TRUE;
  39. }
  40. return FALSE;
  41. }
  42. /***LP CreateInfFile - Create an INF file from an hmodule
  43. *
  44. * ENTRY
  45. * hm - hmodule that contains the REGINST resource
  46. * pszInfFileName -> the location to get the INF filename
  47. *
  48. * EXIT
  49. * Standard API return
  50. */
  51. HRESULT CreateInfFile(HMODULE hm, LPTSTR pszInfFileName, DWORD *pdwFileSize)
  52. {
  53. HRESULT hr = E_FAIL;
  54. TCHAR szInfFilePath[MAX_PATH] = { 0 };
  55. LPVOID pvInfData;
  56. HRSRC hrsrcInfData;
  57. DWORD cbInfData, cbWritten;
  58. HANDLE hfileInf = INVALID_HANDLE_VALUE;
  59. if ( pdwFileSize )
  60. *pdwFileSize = 0;
  61. if (GetTempPath(ARRAYSIZE(szInfFilePath), szInfFilePath) > ARRAYSIZE(szInfFilePath))
  62. {
  63. goto Cleanup;
  64. }
  65. if ( !IsGoodDir( szInfFilePath ) )
  66. {
  67. GetWindowsDirectory( szInfFilePath, sizeof(szInfFilePath) );
  68. }
  69. if (GetTempFileName(szInfFilePath, TEXT("RGI"), 0, pszInfFileName) == 0)
  70. {
  71. goto Cleanup;
  72. }
  73. hrsrcInfData = FindResource(hm, TEXT("REGINST"), TEXT("REGINST"));
  74. if (hrsrcInfData == NULL)
  75. {
  76. goto Cleanup;
  77. }
  78. cbInfData = SizeofResource(hm, hrsrcInfData);
  79. pvInfData = LockResource(LoadResource(hm, hrsrcInfData));
  80. if (pvInfData == NULL)
  81. {
  82. goto Cleanup;
  83. }
  84. WritePrivateProfileString( NULL, NULL, NULL, pszInfFileName );
  85. hfileInf = CreateFile(pszInfFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
  86. FILE_ATTRIBUTE_NORMAL, NULL);
  87. if (hfileInf == INVALID_HANDLE_VALUE)
  88. {
  89. goto Cleanup;
  90. }
  91. if ((WriteFile(hfileInf, pvInfData, cbInfData, &cbWritten, NULL) == FALSE) ||
  92. (cbWritten != cbInfData))
  93. {
  94. goto Cleanup;
  95. }
  96. if ( pdwFileSize )
  97. *pdwFileSize = cbWritten;
  98. hr = S_OK;
  99. Cleanup:
  100. if (hfileInf != INVALID_HANDLE_VALUE)
  101. {
  102. CloseHandle(hfileInf);
  103. }
  104. return hr;
  105. }
  106. #if 0
  107. LPTSTR CheckPrefix(LPTSTR lpszStr, LPCTSTR lpszSub )
  108. {
  109. int ilen;
  110. TCHAR chTmp;
  111. LPTSTR lpTmp = NULL;
  112. ilen = lstrlen( lpszSub );
  113. lpTmp = lpszStr;
  114. while ( ilen && *lpTmp )
  115. {
  116. lpTmp = CharNext( lpTmp );
  117. ilen--;
  118. }
  119. chTmp = *lpTmp;
  120. *lpTmp = '\0';
  121. if ( lstrcmpi( lpszSub, lpszStr ) )
  122. {
  123. *lpTmp = chTmp;
  124. lpTmp = NULL;
  125. }
  126. else
  127. *lpTmp = chTmp;
  128. return lpTmp;
  129. }
  130. #endif
  131. BOOL ReplaceSubString( LPSTR pszOutLine, LPSTR pszOldLine, LPCSTR pszSubStr, LPCSTR pszSubReplacement )
  132. {
  133. LPSTR lpszStart = NULL;
  134. LPSTR lpszNewLine;
  135. LPSTR lpszCur;
  136. BOOL bFound = FALSE;
  137. int ilen;
  138. lpszCur = pszOldLine;
  139. lpszNewLine = pszOutLine;
  140. while ( lpszStart = ANSIStrStrI( lpszCur, pszSubStr ) )
  141. {
  142. // this module path has the systemroot
  143. ilen = (int)(lpszStart - lpszCur);
  144. if ( ilen )
  145. {
  146. lstrcpyn( lpszNewLine, lpszCur, ilen + 1 );
  147. lpszNewLine += ilen;
  148. }
  149. lstrcpy( lpszNewLine, pszSubReplacement );
  150. lpszCur = lpszStart + lstrlen(pszSubStr);
  151. lpszNewLine += lstrlen(pszSubReplacement);
  152. bFound = TRUE;
  153. }
  154. lstrcpy( lpszNewLine, lpszCur );
  155. return bFound;
  156. }
  157. //==========================================================================================
  158. //
  159. //==========================================================================================
  160. BOOL AddEnvInPath( PSTR pszOldPath, PSTR pszNew )
  161. {
  162. CHAR szBuf[MAX_PATH];
  163. CHAR szBuf2[MAX_PATH];
  164. CHAR szEnvVar[100];
  165. CHAR szReplaceStr[100];
  166. CHAR szSysDrv[5];
  167. BOOL bFound = FALSE;
  168. BOOL bRet;
  169. LPSTR pszFinalStr;
  170. pszFinalStr = pszOldPath;
  171. // replace c:\winnt Windows folder
  172. if ( GetEnvironmentVariable( "SystemRoot", szEnvVar, ARRAYSIZE(szEnvVar) ) )
  173. {
  174. if ( ReplaceSubString( szBuf, pszFinalStr, szEnvVar, "%SystemRoot%" ) )
  175. {
  176. bFound = TRUE;
  177. pszFinalStr = szBuf;
  178. }
  179. }
  180. if ( GetProgramFilesDir( szEnvVar, sizeof(szEnvVar) ) &&
  181. GetEnvironmentVariable( "SystemDrive", szSysDrv, ARRAYSIZE(szSysDrv) ) )
  182. {
  183. // Get the replacement string first, so c:\program files replacement is
  184. // %SystemDrive%\program files or %ProgramFiles% if >= WINNT50
  185. // Replace the c:\Program Files folder
  186. //
  187. if ( ctx.wOSVer >= _OSVER_WINNT50 )
  188. {
  189. if ( ReplaceSubString( szBuf2, pszFinalStr, szEnvVar, "%ProgramFiles%" ) )
  190. {
  191. bFound = TRUE;
  192. lstrcpy( szBuf, szBuf2 );
  193. pszFinalStr = szBuf;
  194. }
  195. }
  196. // Replace the c: System Drive letter
  197. if ( ReplaceSubString( szBuf2, pszFinalStr, szSysDrv, "%SystemDrive%" ) )
  198. {
  199. lstrcpy( szBuf, szBuf2 );
  200. pszFinalStr = szBuf;
  201. bFound = TRUE;
  202. }
  203. }
  204. // this way, if caller pass the same location for both params, still OK.
  205. if ( bFound || ( pszNew != pszOldPath ) )
  206. lstrcpy( pszNew, pszFinalStr );
  207. return bFound;
  208. }
  209. //==========================================================================================
  210. //
  211. //==========================================================================================
  212. BOOL MySmartWrite( LPCSTR pcszSection, LPCSTR pcszKey, LPCSTR pcszValue, LPCSTR pcszFilename, DWORD dwFileSize )
  213. {
  214. DWORD cbData, cbWritten = 0;
  215. BOOL bRet = FALSE;
  216. if ( dwFileSize <= FILESIZE_63K )
  217. {
  218. bRet = WritePrivateProfileString( pcszSection, pcszKey, pcszValue, pcszFilename );
  219. }
  220. else
  221. {
  222. HANDLE hfileInf = INVALID_HANDLE_VALUE;
  223. LPSTR pszBuf = NULL;
  224. const char c_szLineTmplate[] = "%s=\"%s\"\r\n";
  225. const char c_szLineTmplate2[] = "%s=%s\r\n";
  226. pszBuf = LocalAlloc( LPTR, 1024 );
  227. if ( !pszBuf )
  228. return bRet;
  229. hfileInf = CreateFile( pcszFilename, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS,
  230. FILE_ATTRIBUTE_NORMAL, NULL);
  231. if (hfileInf == INVALID_HANDLE_VALUE)
  232. {
  233. if ( pszBuf )
  234. LocalFree( pszBuf );
  235. return bRet;
  236. }
  237. if ( SetFilePointer( hfileInf, 0 , NULL, FILE_END ) != 0xFFFFFFFF )
  238. {
  239. if ( *pcszValue != '"' )
  240. wsprintf( pszBuf, c_szLineTmplate, pcszKey, pcszValue );
  241. else
  242. wsprintf( pszBuf, c_szLineTmplate2, pcszKey, pcszValue );
  243. cbData = lstrlen(pszBuf); // key="value"\r\n
  244. WriteFile(hfileInf, pszBuf, cbData, &cbWritten, NULL);
  245. bRet = (cbData == cbWritten);
  246. }
  247. CloseHandle(hfileInf);
  248. if ( pszBuf )
  249. LocalFree( pszBuf );
  250. }
  251. return bRet;
  252. }
  253. /***LP WritePredefinedStrings - Write all predefined strings to an INF
  254. *
  255. * ENTRY
  256. * pszInfFileName -> name of INF file
  257. * hm - hmodule of caller
  258. *
  259. * EXIT
  260. * Standard API return
  261. */
  262. HRESULT WritePredefinedStrings( LPCTSTR pszInfFileName, HMODULE hm, DWORD dwFileSize )
  263. {
  264. HRESULT hr = E_FAIL;
  265. TCHAR szModulePath[MAX_PATH + 2];
  266. BOOL bSysModPath = FALSE;
  267. szModulePath[0] = '"';
  268. if (GetModuleFileName(hm, &szModulePath[1], ARRAYSIZE(szModulePath) - 2) == 0)
  269. {
  270. goto Cleanup;
  271. }
  272. lstrcat( szModulePath, "\"" );
  273. MySmartWrite(TEXT("Strings"), TEXT("_MOD_PATH"), szModulePath, pszInfFileName, dwFileSize);
  274. if ( CheckOSVersion() )
  275. {
  276. // BOOL bFound = FALSE;
  277. if ( ctx.wOSVer >= _OSVER_WINNT40 )
  278. {
  279. if ( AddEnvInPath( szModulePath, szModulePath) )
  280. {
  281. MySmartWrite(TEXT("Strings"), TEXT("_SYS_MOD_PATH"), szModulePath, pszInfFileName, dwFileSize);
  282. bSysModPath = TRUE;
  283. }
  284. }
  285. }
  286. if ( !bSysModPath )
  287. MySmartWrite(TEXT("Strings"), TEXT("_SYS_MOD_PATH"), szModulePath, pszInfFileName, dwFileSize);
  288. hr = S_OK;
  289. Cleanup:
  290. return hr;
  291. }
  292. /***LP WriteCallerStrings - Write caller supplied strings to an INF
  293. *
  294. * ENTRY
  295. * pszInfFileName -> name of INF file
  296. * hm - hmodule of caller
  297. * pstTable - caller supplied string table
  298. *
  299. * EXIT
  300. * Standard API return
  301. */
  302. HRESULT WriteCallerStrings(LPCTSTR pszInfFileName, HMODULE hm, LPCSTRTABLE pstTable, DWORD dwFileSize)
  303. {
  304. HRESULT hr = E_FAIL;
  305. TCHAR szValue[MAX_PATH];
  306. DWORD i;
  307. LPSTRENTRY pse;
  308. TCHAR szQuoteValue[MAX_PATH];
  309. LPTSTR lpValue;
  310. for (i=0, pse=pstTable->pse; i<pstTable->cEntries; i++, pse++)
  311. {
  312. if (IsBadReadPtr(pse, SIZEOF(*pse)))
  313. {
  314. goto Cleanup;
  315. }
  316. if (IS_RESOURCE(pse->pszValue))
  317. {
  318. if (LoadString(hm, (UINT)(ULONG_PTR)(pse->pszValue), szValue, ARRAYSIZE(szValue)) == 0)
  319. {
  320. goto Cleanup;
  321. }
  322. else
  323. lpValue = szValue;
  324. }
  325. else
  326. lpValue = pse->pszValue;
  327. if ( *lpValue != '"' )
  328. {
  329. // if no quote, insert it
  330. szQuoteValue[0] = '"';
  331. lstrcpy( &szQuoteValue[1], lpValue );
  332. lstrcat( szQuoteValue, "\"" );
  333. lpValue = szQuoteValue;
  334. }
  335. MySmartWrite(TEXT("Strings"), pse->pszName, lpValue, pszInfFileName, dwFileSize);
  336. }
  337. hr = S_OK;
  338. Cleanup:
  339. return hr;
  340. }
  341. BOOL GetRollbackSection( LPCSTR pcszModule, LPSTR pszSec, DWORD dwSize )
  342. {
  343. HKEY hKey;
  344. TCHAR szBuf[MAX_PATH];
  345. DWORD dwTmp;
  346. BOOL fRet = FALSE;
  347. lstrcpy( szBuf, REGKEY_SAVERESTORE );
  348. AddPath( szBuf, pcszModule );
  349. if ( RegCreateKeyEx( HKEY_LOCAL_MACHINE, szBuf, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ,
  350. NULL, &hKey, &dwTmp ) == ERROR_SUCCESS )
  351. {
  352. dwTmp = dwSize;
  353. if ( (RegQueryValueEx( hKey, REGVAL_BKINSTSEC, NULL, NULL, pszSec, &dwTmp ) == ERROR_SUCCESS) && *pszSec )
  354. fRet = TRUE;
  355. RegCloseKey( hKey );
  356. }
  357. return fRet;
  358. }
  359. /***LP ExecuteInfSection - Ask RunSetupCommand to execute an INF section
  360. *
  361. * ENTRY
  362. * pszInfFileName -> name of INF file
  363. * pszInfSection -> section to execute
  364. *
  365. * EXIT
  366. * Standard API return
  367. */
  368. HRESULT ExecuteInfSection(LPCTSTR pszInfFileName, LPCTSTR pszInfSection)
  369. {
  370. HRESULT hr = E_FAIL;
  371. TCHAR szTempPath[MAX_PATH];
  372. TCHAR szBuf[MAX_PATH];
  373. BOOL fSavedContext = FALSE;
  374. DWORD dwFlags = 0;
  375. if (!SaveGlobalContext())
  376. {
  377. goto Cleanup;
  378. }
  379. fSavedContext = TRUE;
  380. // get the source dir
  381. if (GetTempPath(ARRAYSIZE(szTempPath), szTempPath) > ARRAYSIZE(szTempPath))
  382. {
  383. goto Cleanup;
  384. }
  385. // we check if this caller needs to do save/rollback, or just simple GenInstall
  386. if (SUCCEEDED(GetTranslatedString(pszInfFileName, pszInfSection, ADVINF_MODNAME, szBuf, ARRAYSIZE(szBuf), NULL)))
  387. {
  388. dwFlags = GetTranslatedInt(pszInfFileName, pszInfSection, ADVINF_FLAGS, 0);
  389. }
  390. if ( (dwFlags & ALINF_BKINSTALL) || (dwFlags & ALINF_ROLLBKDOALL) || (dwFlags & ALINF_ROLLBACK) )
  391. {
  392. CABINFO cabInfo;
  393. ZeroMemory( &cabInfo, sizeof(CABINFO) );
  394. cabInfo.pszInf = (LPSTR)pszInfFileName;
  395. lstrcpy( cabInfo.szSrcPath, szTempPath );
  396. cabInfo.dwFlags = dwFlags;
  397. if ( dwFlags & ALINF_BKINSTALL )
  398. {
  399. cabInfo.pszSection = (LPSTR)pszInfSection;
  400. }
  401. else
  402. {
  403. if ( !GetRollbackSection( szBuf, szTempPath, ARRAYSIZE(szTempPath) ) )
  404. {
  405. hr = E_UNEXPECTED;
  406. goto Cleanup;
  407. }
  408. cabInfo.pszSection = szTempPath;
  409. }
  410. hr = ExecuteCab( NULL, &cabInfo, NULL );
  411. }
  412. else
  413. {
  414. hr = RunSetupCommand(INVALID_HANDLE_VALUE, pszInfFileName, pszInfSection,
  415. szTempPath, NULL, NULL, RSC_FLAG_INF | RSC_FLAG_QUIET,
  416. NULL);
  417. }
  418. Cleanup:
  419. if (fSavedContext)
  420. {
  421. RestoreGlobalContext();
  422. }
  423. return hr;
  424. }
  425. /***EP RegInstall - Install a registry INF
  426. *
  427. * @doc API REGINSTALL
  428. *
  429. * @api STDAPI | RegInstall | Install a registry INF
  430. *
  431. * @parm HMODULE | hm | The hmodule of the caller. The INF is extracted
  432. * from the module's resources (type="REGINST", name="REGINST").
  433. *
  434. * @parm LPCTSTR | pszSection | The section of the INF to execute.
  435. *
  436. * @parm LPCSTRTABLE | pstTable | A table of string mappings.
  437. *
  438. * @rdesc S_OK - registry INF successfully installed.
  439. *
  440. * @rdesc E_FAIL - error installing INF.
  441. */
  442. STDAPI RegInstall(HMODULE hm, LPCTSTR pszSection, LPCSTRTABLE pstTable)
  443. {
  444. HRESULT hr = E_FAIL;
  445. TCHAR szInfFileName[MAX_PATH];
  446. DWORD dwFileSize = 0;
  447. AdvWriteToLog("RegInstall: Section=%1\r\n", pszSection);
  448. //
  449. // Create the INF file.
  450. //
  451. szInfFileName[0] = TEXT('\0');
  452. hr = CreateInfFile(hm, szInfFileName, &dwFileSize);
  453. if (FAILED(hr))
  454. {
  455. goto Cleanup;
  456. }
  457. //
  458. // Write out our predefined strings.
  459. //
  460. hr = WritePredefinedStrings(szInfFileName, hm, dwFileSize);
  461. if (FAILED(hr))
  462. {
  463. goto Cleanup;
  464. }
  465. //
  466. // Write out the user supplied strings.
  467. //
  468. if (pstTable)
  469. {
  470. hr = WriteCallerStrings(szInfFileName, hm, pstTable, dwFileSize);
  471. if (FAILED(hr))
  472. {
  473. goto Cleanup;
  474. }
  475. }
  476. WritePrivateProfileString( NULL, NULL, NULL, szInfFileName );
  477. //
  478. // Execute the INF engine on the INF.
  479. //
  480. hr = ExecuteInfSection(szInfFileName, pszSection);
  481. if (FAILED(hr))
  482. {
  483. goto Cleanup;
  484. }
  485. Cleanup:
  486. //
  487. // Delete the INF file.
  488. //
  489. if (szInfFileName[0])
  490. {
  491. DeleteFile(szInfFileName);
  492. }
  493. AdvWriteToLog("RegInstall: Section=%1 End hr=%2!x!\r\n", pszSection, hr);
  494. return hr;
  495. }