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.

1116 lines
37 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. db.cpp
  5. Abstract:
  6. Database calls for msm generation
  7. Author:
  8. Xiaoyu Wu(xiaoyuw) 01-Aug-2001
  9. --*/
  10. #include "msmgen.h"
  11. #include "msidefs.h"
  12. #include "Msiquery.h"
  13. #include "objbase.h"
  14. #include "coguid.h"
  15. #define NUM_OF_ALLOWED_ATTRIBUTE_ASSEMBLYIDENTITY 6
  16. #define NUM_OF_ALLOWED_ATTRIBUTE_COMCLASS 5
  17. #define NUM_OF_ALLOWED_ATTRIBUTE_TYPELIB 3
  18. static PWSTR s_InsertTableSQL[] =
  19. {
  20. L"INSERT INTO Directory (Directory, Directory_Parent, DefaultDir) VALUES (?, ?, ?)",
  21. L"INSERT INTO Component (Component, ComponentId, Directory_, KeyPath, Attributes, Condition) VALUES (?, ?, ?, ?, 0, '')",
  22. L"INSERT INTO File (File, Component_, FileName, Sequence, FileSize, Version, Language, Attributes) VALUES (?, ?, ?, ?, '0', '1.0.0.0', '0', 0)",
  23. L"INSERT INTO MsiAssembly (Component_, Feature_, File_Manifest, File_Application, Attributes) VALUES (?, ?, ?, '', 1)",
  24. L"INSERT INTO MsiAssemblyName (Component_, Name, Value) VALUES (?, ?, ?)",
  25. L"INSERT INTO ModuleSignature (ModuleID, Version, Language) VALUES (?, ?, 0)",
  26. L"INSERT INTO ModuleComponents (Component, ModuleID, Language) VALUES (?, ?, 0)",
  27. L"INSERT INTO Property (Property, Value) VALUES (?, ?)",
  28. L"INSERT INTO ProgId (ProgId, Class_, Description, ProgId_Parent, Icon_, IconIndex) VALUES (?, ?, ?, NULL, NULL, NULL)",
  29. L"INSERT INTO Class (CLSID, Component_, ProgId_Default, Description, Feature_, Context, AppId_, FileTypeMask, Icon_, IconIndex, DefInprocHandler, Argument, Attributes)"
  30. L"VALUES (?, ?, ?, ?, ?, 'InprocServer32', NULL, NULL, NULL, NULL, NULL, NULL, 0)",
  31. L"INSERT INTO TypeLib (LibID, Component_, Version, Feature_, Language, Description, Directory_, Cost)"
  32. L"VALUES (?, ?, ?, ?, 0, NULL, NULL, 0)"
  33. };
  34. HRESULT ExecuteDeleteFromSQL(PCWSTR szTablename, PCWSTR szId, PCWSTR szValue)
  35. {
  36. HRESULT hr = S_OK;
  37. WCHAR pwszSQL[MAX_PATH];
  38. PMSIHANDLE hView = NULL;
  39. swprintf(pwszSQL, L"DELETE FROM `%s` WHERE `%s`='%s'", szTablename, szId, szValue);
  40. IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiDatabaseOpenViewW(g_MsmInfo.m_hdb, pwszSQL, &hView));
  41. IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiViewExecute(hView, NULL));
  42. Exit:
  43. return hr;
  44. }
  45. DWORD g_FileSequenceNumber = 0;
  46. HRESULT ExecuteDropTableSQL(PCWSTR pszTableName)
  47. {
  48. WCHAR pwszSQL[MAX_PATH];
  49. HRESULT hr = S_OK;
  50. PMSIHANDLE hView = NULL;
  51. MSICONDITION con;
  52. con = MsiDatabaseIsTablePersistent(g_MsmInfo.m_hdb, pszTableName);
  53. if (con == MSICONDITION_NONE)
  54. {
  55. hr = S_OK; // the table does not exist in DB, so do not need to drop the table at all
  56. goto Exit;
  57. }
  58. else if (con != MSICONDITION_TRUE)
  59. SETFAIL_AND_EXIT;
  60. //
  61. // drop the table
  62. //
  63. swprintf(pwszSQL, L"DROP TABLE `%s`", pszTableName);
  64. //
  65. // ignore the error for drop table because this table maybe non-exist at all
  66. //
  67. IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiDatabaseOpenViewW(g_MsmInfo.m_hdb, pwszSQL, &hView));
  68. IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiViewExecute(hView, NULL));
  69. Exit:
  70. return hr;
  71. }
  72. HRESULT ExecuteInsertTableSQL(DWORD tableIndex, UINT cRecords, ...)
  73. {
  74. PMSIHANDLE hView;
  75. PMSIHANDLE hRecord = NULL;
  76. PCWSTR pwszRecord = NULL;
  77. va_list ap;
  78. HRESULT hr = S_OK;
  79. PWSTR pwszSQL = NULL;
  80. pwszSQL = s_InsertTableSQL[tableIndex];
  81. //
  82. // create records
  83. //
  84. switch (tableIndex){
  85. case OPT_FILE:
  86. hRecord = ::MsiCreateRecord(cRecords + 1);
  87. break;
  88. case OPT_DIRECTORY:
  89. case OPT_COMPONENT:
  90. case OPT_MSIASSEMBLY:
  91. case OPT_MSIASSEMBLYNAME:
  92. case OPT_MODULESIGNATURE:
  93. case OPT_MODULECOMPONENTS:
  94. case OPT_PROPERTY:
  95. case OPT_PROGID:
  96. case OPT_CLASS:
  97. case OPT_TYPELIB:
  98. hRecord = ::MsiCreateRecord(cRecords);
  99. break;
  100. default:
  101. SETFAIL_AND_EXIT;
  102. }
  103. if (hRecord == NULL)
  104. SETFAIL_AND_EXIT;
  105. //
  106. // get parameters
  107. //
  108. va_start(ap, cRecords);
  109. for (DWORD i=0; i<cRecords; i++)
  110. {
  111. pwszRecord = va_arg(ap, PCWSTR);
  112. if ((tableIndex == OPT_TYPELIB) && (i == 2)) // set version for typelib
  113. {
  114. UINT x = _wtoi(pwszRecord);
  115. IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiRecordSetInteger(hRecord, i+1, x));
  116. }
  117. else
  118. IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiRecordSetStringW(hRecord, i+1, pwszRecord));
  119. }
  120. //
  121. // for fileTable, add a sequence number here
  122. //
  123. if (tableIndex == OPT_FILE)
  124. {
  125. g_FileSequenceNumber ++;
  126. IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiRecordSetInteger(hRecord, cRecords + 1 , g_FileSequenceNumber));
  127. }
  128. IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiDatabaseOpenViewW(g_MsmInfo.m_hdb, pwszSQL, &hView));
  129. IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiViewExecute(hView, hRecord));
  130. Exit:
  131. va_end(ap);
  132. return hr;
  133. }
  134. //
  135. // check a table with a name-value pair of its identifier
  136. //
  137. HRESULT ExecuteQuerySQL(PCWSTR szTableName, PCWSTR szKeyName, PCWSTR szKeyValue, BOOL & fExist, MSIHANDLE * hOutRecord)
  138. {
  139. WCHAR pwszSQL[MAX_PATH];
  140. HRESULT hr = S_OK;
  141. PMSIHANDLE hView = NULL;
  142. MSIHANDLE hRecord;
  143. MSIHANDLE * phRecord = hOutRecord;
  144. if (phRecord == NULL)
  145. phRecord = &hRecord;
  146. fExist = FALSE;
  147. swprintf(pwszSQL, L"SELECT * FROM `%s` WHERE `%s`='%s'", szTableName, szKeyName, szKeyValue);
  148. IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiDatabaseOpenViewW(g_MsmInfo.m_hdb, pwszSQL, &hView));
  149. IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiViewExecute(hView, NULL));
  150. UINT err = ::MsiViewFetch(hView, phRecord);
  151. if ((err == ERROR_NO_MORE_ITEMS) || ((err == ERROR_SUCCESS) && (phRecord == NULL)))
  152. fExist = FALSE;
  153. else if (err != ERROR_SUCCESS)
  154. SET_HRERR_AND_EXIT(err);
  155. else
  156. fExist = TRUE;
  157. Exit:
  158. if (phRecord == &hRecord)
  159. MsiCloseHandle(hRecord);
  160. return hr;
  161. }
  162. HRESULT ExecuteUpdateSQL(PCWSTR szTableName, PCWSTR KeyName, PCWSTR KeyValue, PCWSTR ColumnName, PCWSTR NewValue)
  163. {
  164. WCHAR pwszSQL[MAX_PATH];
  165. HRESULT hr = S_OK;
  166. PMSIHANDLE hView = NULL;
  167. MSIHANDLE * hRecord = NULL;
  168. BOOL fExist = FALSE;
  169. swprintf(pwszSQL, L"UPDATE '%s' SET `%s` = '%s' WHERE '%s'='%s'",
  170. szTableName, ColumnName, NewValue, KeyName, KeyValue);
  171. IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiDatabaseOpenViewW(g_MsmInfo.m_hdb, pwszSQL, &hView));
  172. IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiViewExecute(hView, NULL));
  173. Exit:
  174. return hr;
  175. }
  176. HRESULT GetShortLongFileNamePair(PCWSTR fullpath, SIZE_T cch, CStringBuffer & namepair)
  177. {
  178. WCHAR shortname[MAX_PATH];
  179. HRESULT hr = S_OK;
  180. PWSTR p = NULL;
  181. DWORD ret = GetShortPathNameW(
  182. fullpath,
  183. shortname,
  184. NUMBER_OF(shortname));
  185. if ( ret == 0 )
  186. {
  187. hr = HRESULT_FROM_WIN32(::GetLastError());
  188. goto Exit;
  189. }
  190. if (ret > NUMBER_OF(shortname))
  191. {
  192. hr = ERROR_INSUFFICIENT_BUFFER;
  193. goto Exit;
  194. }
  195. p = wcsrchr(shortname, L'\\');
  196. p ++ ;
  197. IFFALSE_EXIT(namepair.Win32Assign(p, wcslen(p)));
  198. IFFALSE_EXIT(namepair.Win32Append(L"|", 1));
  199. p = wcsrchr(fullpath, L'\\');
  200. p++;
  201. IFFALSE_EXIT(namepair.Win32Append(p, wcslen(p)));
  202. Exit:
  203. return hr;
  204. }
  205. //
  206. // Function:
  207. // - Directory Table could be set without open the manifest
  208. // - write 2 entry to Directory Table for downlevel
  209. // - only write the record when they are not exist in the DB
  210. //
  211. HRESULT SetDirectoryTable()
  212. {
  213. HRESULT hr = S_OK;
  214. BOOL fExist;
  215. CStringBuffer sbSystemFolder;
  216. IFFAILED_EXIT(ExecuteQuerySQL(L"Directory", L"Directory", L"TARGETDIR", fExist, NULL));
  217. if (!fExist)
  218. {
  219. IFFAILED_EXIT(ExecuteInsertTableSQL(
  220. OPT_DIRECTORY,
  221. NUMBER_OF_PARAM_TO_INSERT_TABLE_DIRECTORY,
  222. MAKE_PCWSTR(L"TARGETDIR"), // the re-cast is necessary for va_list
  223. MAKE_PCWSTR(L""),
  224. MAKE_PCWSTR(L"SourceDir")));
  225. }
  226. // for downlevel installation : copy files into SystemFolders
  227. IFFALSE_EXIT(sbSystemFolder.Win32Assign(SYSTEM_FOLDER, NUMBER_OF(SYSTEM_FOLDER)-1));
  228. IFFALSE_EXIT(sbSystemFolder.Win32Append(g_MsmInfo.m_sbModuleGuidStr));
  229. IFFAILED_EXIT(ExecuteQuerySQL(L"Directory", L"Directory", sbSystemFolder, fExist, NULL));
  230. if (!fExist)
  231. {
  232. IFFAILED_EXIT(ExecuteInsertTableSQL(
  233. OPT_DIRECTORY,
  234. NUMBER_OF_PARAM_TO_INSERT_TABLE_DIRECTORY,
  235. MAKE_PCWSTR(sbSystemFolder), // the re-cast is necessary for va_list
  236. MAKE_PCWSTR(L"TARGETDIR"),
  237. MAKE_PCWSTR(L"System:.")));
  238. }
  239. Exit:
  240. return hr;
  241. }
  242. //
  243. // Function:
  244. // - add manifest and catalog into the cabinet
  245. // - add manifest and catalog into FileTable
  246. //
  247. // because this function used ComponentIdentifier, it has to wait until ComponentIdentifier is set
  248. // and it is set to be the name of the assembly
  249. //
  250. HRESULT SetManifestAndCatalog()
  251. {
  252. HRESULT hr = S_OK;
  253. CStringBuffer sbBakFileName;
  254. CStringBuffer sbNamePair;
  255. CurrentAssemblyReset;
  256. //
  257. // add manifest into FileTable and Cabinet
  258. //
  259. IFFALSE_EXIT(sbBakFileName.Win32Assign(curAsmInfo.m_sbManifestFileName));
  260. IFFALSE_EXIT(curAsmInfo.m_sbManifestFileName.Win32Append(g_MsmInfo.m_sbModuleGuidStr));
  261. curAsmInfo.m_sbAssemblyPath.Left(curAsmInfo.m_CchAssemblyPath);
  262. IFFALSE_EXIT(curAsmInfo.m_sbAssemblyPath.Win32Append(sbBakFileName));
  263. IFFAILED_EXIT(GetShortLongFileNamePair(curAsmInfo.m_sbAssemblyPath, curAsmInfo.m_sbAssemblyPath.Cch(), sbNamePair));
  264. IFFAILED_EXIT(ExecuteInsertTableSQL(
  265. OPT_FILE,
  266. NUMBER_OF_PARAM_TO_INSERT_TABLE_FILE,
  267. MAKE_PCWSTR(curAsmInfo.m_sbManifestFileName), // sfp.manifest.123434545
  268. MAKE_PCWSTR(curAsmInfo.m_sbComponentIdentifier),
  269. MAKE_PCWSTR(sbNamePair))); // sfp.manifest
  270. // add manifest to the cabinet
  271. IFFAILED_EXIT(AddFileToCabinetW( curAsmInfo.m_sbAssemblyPath, // fullpath : c:\tests\sfp\sfp.manifest
  272. curAsmInfo.m_sbAssemblyPath.Cch(),
  273. curAsmInfo.m_sbManifestFileName, // identifier in FILE : sfp.manifest.1234234234234234
  274. curAsmInfo.m_sbManifestFileName.Cch()));
  275. //
  276. // add catalog into FileTable and Cabinet
  277. //
  278. IFFALSE_EXIT(sbBakFileName.Win32ChangePathExtension(CATALOG_FILE_EXT, NUMBER_OF(CATALOG_FILE_EXT) -1, eAddIfNoExtension));
  279. IFFALSE_EXIT(curAsmInfo.m_sbCatalogFileName.Win32Append(g_MsmInfo.m_sbModuleGuidStr));
  280. curAsmInfo.m_sbAssemblyPath.Left(curAsmInfo.m_CchAssemblyPath);
  281. IFFALSE_EXIT(curAsmInfo.m_sbAssemblyPath.Win32Append(sbBakFileName));
  282. IFFAILED_EXIT(GetShortLongFileNamePair(curAsmInfo.m_sbAssemblyPath, curAsmInfo.m_sbAssemblyPath.Cch(), sbNamePair));
  283. IFFAILED_EXIT(ExecuteInsertTableSQL(
  284. OPT_FILE,
  285. NUMBER_OF_PARAM_TO_INSERT_TABLE_FILE,
  286. MAKE_PCWSTR(curAsmInfo.m_sbCatalogFileName), // sfp.cat.123434345345
  287. MAKE_PCWSTR(curAsmInfo.m_sbComponentIdentifier),
  288. MAKE_PCWSTR(sbNamePair))); // sfp.cat
  289. // add catalog to the cabinet
  290. IFFAILED_EXIT(AddFileToCabinetW(curAsmInfo.m_sbAssemblyPath, // fullpath : c:\tests\sfp\sfp.cat
  291. curAsmInfo.m_sbAssemblyPath.Cch(),
  292. curAsmInfo.m_sbCatalogFileName, //
  293. curAsmInfo.m_sbCatalogFileName.Cch()));
  294. Exit:
  295. return hr;
  296. }
  297. //
  298. // Function:
  299. // Dump the cabinet File into a TemporaryFile
  300. // Param:
  301. // OUT WCHAR pszCabFile[] : store the temporary cabinet file
  302. // PMSIHANDLE hRecord: the record which contain the stream of a cabinet
  303. //
  304. HRESULT DumpCABFromMsm(char *pszFilename, DWORD cchFileName, PMSIHANDLE hRecord)
  305. {
  306. HRESULT hr = S_OK;
  307. char buf[1024]; // !!!!fci and fdi are ansi apis
  308. DWORD cbBuf;
  309. DWORD cbBytesWritten;
  310. CStringBuffer sbFilename;
  311. HANDLE hd = INVALID_HANDLE_VALUE;
  312. //
  313. // generate a filename for temporary cabinet
  314. // use the big buffer to generate a filename
  315. //
  316. DWORD num = ExpandEnvironmentStringsA(MSM_TEMP_CABIN_FILE, pszFilename, cchFileName);
  317. if ((num == 0) || (num > cchFileName))
  318. SETFAIL_AND_EXIT;
  319. DWORD dwAttributes = GetFileAttributesA(pszFilename);
  320. if ( dwAttributes != (DWORD)(-1))
  321. {
  322. if (dwAttributes & FILE_ATTRIBUTE_DIRECTORY)
  323. SET_HRERR_AND_EXIT(ERROR_INTERNAL_ERROR);
  324. //
  325. // delete the file before create it, if can not delete, then it is an error,
  326. // stop right here
  327. //
  328. IFFALSE_EXIT(DeleteFileA(pszFilename));
  329. }
  330. hd = CreateFileA(pszFilename, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_TEMPORARY, NULL);
  331. if (hd == INVALID_HANDLE_VALUE)
  332. SET_HRERR_AND_EXIT(::GetLastError());
  333. //
  334. // get the stream by reading out bytes from the record block by block
  335. //
  336. do {
  337. cbBuf = sizeof(buf); // using bytes, not cch
  338. IF_NOTSUCCESS_SET_HRERR_EXIT(MsiRecordReadStream(hRecord, 2, buf, &cbBuf));
  339. if (cbBuf != 0)
  340. {
  341. cbBytesWritten = 0;
  342. IFFALSE_EXIT(WriteFile(hd, buf, cbBuf, &cbBytesWritten, NULL));
  343. }
  344. }while(cbBuf > 0 );
  345. IFFALSE_EXIT(CloseHandle(hd));
  346. hd = INVALID_HANDLE_VALUE;
  347. Exit:
  348. if (hd != INVALID_HANDLE_VALUE)
  349. CloseHandle(hd);
  350. return hr;
  351. }
  352. //
  353. // (0) ASSERT the database has opened and the cabient has created
  354. // (1) check whether this is a mergemodule.cab in _Stream table.
  355. // (2) if so, extract all files from this cab,
  356. // (3) delete the entry from _StreamTable
  357. // (4) add all files into new cabinet
  358. //
  359. HRESULT PrepareMsmCabinet()
  360. {
  361. if (g_MsmInfo.m_enumGenMode == MSMGEN_OPR_NEW)
  362. return S_OK;
  363. HRESULT hr = S_OK;
  364. MSIHANDLE hRecord = NULL;
  365. BOOL fExist = FALSE;
  366. char szCabFile[MAX_PATH];
  367. ASSERT_NTC(g_MsmInfo.m_hdb != NULL);
  368. ASSERT_NTC(g_MsmInfo.m_hfci != NULL);
  369. IFFAILED_EXIT(ExecuteQuerySQL(L"_Streams", L"Name", MERGEMODULE_CABINET_FILENAME, fExist, &hRecord));
  370. if (fExist)
  371. {
  372. if (g_MsmInfo.m_enumGenMode == MSMGEN_OPR_REGEN)
  373. {
  374. IFFAILED_EXIT(ExecuteDeleteFromSQL(L"_Streams", L"Name", MERGEMODULE_CABINET_FILENAME));
  375. }
  376. else
  377. {
  378. ASSERT_NTC(g_MsmInfo.m_enumGenMode == MSMGEN_OPR_ADD);
  379. IFFAILED_EXIT(DumpCABFromMsm(szCabFile, sizeof(szCabFile), hRecord));
  380. IFFAILED_EXIT(MoveFilesInCabinetA(szCabFile));
  381. IFFAILED_EXIT(ExecuteDeleteFromSQL(L"_Streams", L"Name", MERGEMODULE_CABINET_FILENAME));
  382. }
  383. }
  384. Exit:
  385. if (GetFileAttributes(szCabFile) != -1)
  386. DeleteFileA(szCabFile);
  387. return hr;
  388. }
  389. HRESULT PrepareDatabase()
  390. {
  391. HRESULT hr = S_OK;
  392. //
  393. // open the msm, make it ready for READ_WRITE
  394. //
  395. IFFAILED_EXIT(OpenMsmFileForMsmGen(g_MsmInfo.m_sbMsmFileName));
  396. //
  397. // the database has opened
  398. //
  399. IFFAILED_EXIT(PrepareMsmCabinet());
  400. //
  401. // get moduleID or generate a new one
  402. //
  403. IFFAILED_EXIT(SetModuleID());
  404. //
  405. // for "-op regen",
  406. // (0) for whatever case, we keep the directory table because it is manifest-independent
  407. // (1) if component is specified on the command line, we delete most tables except Directory Table;
  408. // (2) Otherwise, we use the old componentID table, so we delete all tables except Component-related Tables, which include
  409. // Component Table, ModuleComponent Table, ModuleSignature Table;
  410. // (3) THERE IS A BIG ASSUMPTION FOR (2): ASSEMBLYNAME IN THE MANIFEST IS NOT CHANGED!
  411. //
  412. // (4) all the tables used by msm would be get imported from msmgen Template file in HRESULT PrepareMsm() call;
  413. //
  414. if (g_MsmInfo.m_enumGenMode == MSMGEN_OPR_REGEN)
  415. {
  416. IFFAILED_EXIT(ExecuteDropTableSQL(L"File"));
  417. IFFAILED_EXIT(ExecuteDropTableSQL(L"MsiAssembly"));
  418. IFFAILED_EXIT(ExecuteDropTableSQL(L"MsiAssemblyName"));
  419. IFFAILED_EXIT(ExecuteDropTableSQL(L"Class"));
  420. IFFAILED_EXIT(ExecuteDropTableSQL(L"TypeLib"));
  421. IFFAILED_EXIT(ExecuteDropTableSQL(L"ProgId"));
  422. if (curAsmInfo.m_sbComponentID.IsEmpty() == FALSE)
  423. {
  424. IFFAILED_EXIT(ExecuteDropTableSQL(L"Component"));
  425. IFFAILED_EXIT(ExecuteDropTableSQL(L"ModuleComponent"));
  426. IFFAILED_EXIT(ExecuteDropTableSQL(L"ModuleSignature"));
  427. }
  428. }
  429. //
  430. // if it is a user msm, make sure it has all the tables needed for msmgen
  431. //
  432. IFFAILED_EXIT(PrepareMsm());
  433. Exit:
  434. return hr;
  435. }
  436. //
  437. // if not specified by the user, ue the same basename as the manifest.
  438. // in any case, extand it to be a fully-qualified path name for this msm
  439. //
  440. HRESULT SetMsmOutputFileName(PCWSTR pszManifestFileName)
  441. {
  442. HRESULT hr = S_OK;
  443. WCHAR tmpbuf[MAX_PATH];
  444. PARAMETER_CHECK_NTC(pszManifestFileName != NULL);
  445. if (g_MsmInfo.m_sbMsmFileName.IsEmpty() == TRUE)
  446. {
  447. // set .msm filename
  448. UINT iRet = GetFullPathNameW(pszManifestFileName, NUMBER_OF(tmpbuf), tmpbuf, NULL);
  449. if ((iRet == 0) || (iRet > NUMBER_OF(tmpbuf)))
  450. {
  451. SET_HRERR_AND_EXIT(::GetLastError());
  452. }
  453. IFFALSE_EXIT(g_MsmInfo.m_sbMsmFileName.Win32Assign(tmpbuf, wcslen(tmpbuf)));
  454. IFFALSE_EXIT(g_MsmInfo.m_sbMsmFileName.Win32ChangePathExtension(MSM_FILE_EXT, NUMBER_OF(MSM_FILE_EXT) -1, eAddIfNoExtension));
  455. }else{
  456. // get fullpath name
  457. UINT iRet = GetFullPathNameW(g_MsmInfo.m_sbMsmFileName, NUMBER_OF(tmpbuf), tmpbuf, NULL);
  458. if ((iRet == 0) || (iRet > NUMBER_OF(tmpbuf)))
  459. {
  460. SET_HRERR_AND_EXIT(::GetLastError());
  461. }
  462. IFFALSE_EXIT(g_MsmInfo.m_sbMsmFileName.Win32Assign(tmpbuf, wcslen(tmpbuf)));
  463. }
  464. //
  465. // Set Cabinet FilePath
  466. //
  467. IFFALSE_EXIT(g_MsmInfo.m_sbCabinet.Win32Assign(g_MsmInfo.m_sbMsmFileName));
  468. IFFALSE_EXIT(g_MsmInfo.m_sbCabinet.Win32RemoveLastPathElement());
  469. IFFALSE_EXIT(g_MsmInfo.m_sbCabinet.Win32EnsureTrailingPathSeparator());
  470. IFFALSE_EXIT(g_MsmInfo.m_sbCabinet.Win32Append(MERGEMODULE_CABINET_FILENAME, NUMBER_OF(MERGEMODULE_CABINET_FILENAME) -1));
  471. Exit:
  472. return hr;
  473. }
  474. //
  475. // Functions:
  476. // (1)get the template msm file
  477. // (2)get the msm output file
  478. // (3)set static contents for some tables
  479. //
  480. HRESULT PrepareMsmOutputFiles(PCWSTR pszManifestFilename)
  481. {
  482. HRESULT hr = S_OK;
  483. CurrentAssemblyReset;
  484. if (g_MsmInfo.m_sbMsmTemplateFile.IsEmpty() == TRUE)
  485. {
  486. //
  487. // get template file from current directory
  488. //
  489. WCHAR path[MAX_PATH];
  490. DWORD dwRet;
  491. dwRet = GetModuleFileNameW(NULL, path, NUMBER_OF(path));
  492. if ((dwRet == 0) || (dwRet >= NUMBER_OF(path)))
  493. SET_HRERR_AND_EXIT(::GetLastError());
  494. IFFALSE_EXIT(g_MsmInfo.m_sbMsmTemplateFile.Win32Assign(path, wcslen(path)));
  495. IFFALSE_EXIT(g_MsmInfo.m_sbMsmTemplateFile.Win32ChangePathExtension(L"msm", 3, eErrorIfNoExtension));
  496. }
  497. if (::GetFileAttributesW(g_MsmInfo.m_sbMsmTemplateFile) == (DWORD) -1)
  498. {
  499. fprintf(stderr, "the specified Msm TemplateFile %S does not exist!\n", g_MsmInfo.m_sbMsmTemplateFile);
  500. SET_HRERR_AND_EXIT(::GetLastError());
  501. }
  502. IFFAILED_EXIT(SetMsmOutputFileName(pszManifestFilename));
  503. //
  504. // initialize the cabinet before the database is initialized because it may needed in
  505. // the mode of "MSMGEN_OPR_ADD"
  506. //
  507. IFFAILED_EXIT(InitializeCabinetForWrite());
  508. //
  509. // prepare the msm files for open
  510. //
  511. IFFAILED_EXIT(PrepareDatabase());
  512. //
  513. // set entries to Directory for downlevel support
  514. //
  515. IFFAILED_EXIT(SetDirectoryTable());
  516. Exit:
  517. return hr;
  518. }
  519. HRESULT PropagateXMLDOMNode(IXMLDOMNode* node, ELEMENT_ALLOWED_ATTRIBUTE rgAllowedAttribute[], DWORD num)
  520. {
  521. HRESULT hr = S_OK;
  522. IXMLDOMNamedNodeMap* pattrs = NULL;
  523. IXMLDOMNode* pChild = NULL;
  524. CStringBuffer tmp;
  525. DWORD j;
  526. CurrentAssemblyReset;
  527. for ( j = 0 ; j < num; j++)
  528. rgAllowedAttribute[j].m_fValued = FALSE;
  529. //
  530. // write MSIAssemblyName table
  531. //
  532. if (SUCCEEDED(node->get_attributes(&pattrs)) && pattrs != NULL)
  533. {
  534. pattrs->nextNode(&pChild);
  535. while (pChild)
  536. {
  537. BSTR name;
  538. pChild->get_nodeName(&name);
  539. for ( j = 0; j < num; j++)
  540. {
  541. if((rgAllowedAttribute[j].m_fValued == FALSE) && (wcscmp(rgAllowedAttribute[j].m_name, name) == 0))
  542. {
  543. VARIANT value;
  544. pChild->get_nodeValue(&value);
  545. if (value.vt != VT_BSTR)
  546. {
  547. hr = E_FAIL;
  548. break;
  549. }
  550. if ( ! rgAllowedAttribute[j].m_value->Win32Assign(V_BSTR(&value), wcslen(V_BSTR(&value))))
  551. hr = HRESULT_FROM_WIN32(::GetLastError());
  552. VariantClear(&value);
  553. if ( !SUCCEEDED(hr))
  554. break;
  555. hr = S_OK;
  556. if (rgAllowedAttribute[j].m_callbackFunc != NULL)
  557. hr = rgAllowedAttribute[j].m_callbackFunc(
  558. rgAllowedAttribute[j].m_name,
  559. *(rgAllowedAttribute[j].m_value));
  560. if ( !SUCCEEDED(hr))
  561. break;
  562. rgAllowedAttribute[j].m_fValued = TRUE;
  563. }
  564. }
  565. //
  566. // cleaning work
  567. //
  568. SysFreeString(name);
  569. pChild->Release();
  570. pChild = NULL;
  571. if (!SUCCEEDED(hr))
  572. {
  573. pattrs->Release();
  574. pattrs = NULL;
  575. goto Exit;
  576. }
  577. pattrs->nextNode(&pChild);
  578. }
  579. pattrs->Release();
  580. pattrs = NULL;
  581. }
  582. Exit:
  583. SAFE_RELEASE_COMPOINTER(pattrs);
  584. SAFE_RELEASE_COMPOINTER(pChild);
  585. return hr;
  586. }
  587. HRESULT MSM_PARSER_DOM_NODE_file(IXMLDOMNode* node)
  588. {
  589. IXMLDOMNamedNodeMap* pattrs = NULL;
  590. IXMLDOMNode* pChild = NULL;
  591. BOOL fFoundFileName = FALSE;
  592. HRESULT hr = S_OK;
  593. CStringBuffer tmpStr;
  594. CStringBuffer ShortLongPair;
  595. DWORD CchFullpathFilename;
  596. CurrentAssemblyReset;
  597. IFFALSE_EXIT(tmpStr.Win32Assign(curAsmInfo.m_sbAssemblyPath));
  598. //
  599. // get the filename from node
  600. //
  601. if (SUCCEEDED(node->get_attributes(&pattrs)) && pattrs != NULL)
  602. {
  603. pattrs->nextNode(&pChild);
  604. while (pChild)
  605. {
  606. BSTR name = NULL;
  607. pChild->get_nodeName(&name);
  608. if (wcscmp(name, L"name") == 0)
  609. {
  610. VARIANT value;
  611. pChild->get_nodeValue(&value);
  612. if (value.vt != VT_BSTR)
  613. {
  614. VariantClear(&value);
  615. hr = E_FAIL;
  616. break;
  617. }
  618. if ( !curAsmInfo.m_sbAssemblyPath.Win32Append(V_BSTR(&value), wcslen(V_BSTR(&value))))
  619. hr = HRESULT_FROM_WIN32(::GetLastError());
  620. VariantClear(&value);
  621. fFoundFileName = TRUE;
  622. }
  623. ::SysFreeString(name);
  624. pChild->Release();
  625. pChild = NULL;
  626. if (!SUCCEEDED(hr)){
  627. pattrs->Release();
  628. pattrs = NULL;
  629. goto Exit;
  630. }
  631. if ( fFoundFileName )
  632. break;
  633. pattrs->nextNode(&pChild);
  634. }
  635. if (pattrs)
  636. {
  637. pattrs->Release();
  638. pattrs = NULL;
  639. }
  640. }
  641. if ( !fFoundFileName)
  642. SETFAIL_AND_EXIT;
  643. CchFullpathFilename = curAsmInfo.m_sbAssemblyPath.GetCchAsDWORD();
  644. //
  645. // get fully qualified filename
  646. //
  647. IFFAILED_EXIT(GetShortLongFileNamePair(curAsmInfo.m_sbAssemblyPath, curAsmInfo.m_sbAssemblyPath.Cch(), ShortLongPair));
  648. //
  649. // check the existence of the file
  650. //
  651. if ( GetFileAttributesW(curAsmInfo.m_sbAssemblyPath) == DWORD(-1))
  652. {
  653. hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  654. goto Exit;
  655. }
  656. //
  657. // get FileIdentifier for this file
  658. //
  659. IFFALSE_EXIT(curAsmInfo.m_sbAssemblyPath.Win32Append(g_MsmInfo.m_sbModuleGuidStr));
  660. //
  661. // add the file to FileTable
  662. //
  663. IFFAILED_EXIT(ExecuteInsertTableSQL(
  664. OPT_FILE,
  665. NUMBER_OF_PARAM_TO_INSERT_TABLE_FILE,
  666. MAKE_PCWSTR(curAsmInfo.m_sbAssemblyPath + curAsmInfo.m_CchAssemblyPath), // a.dll.12223423423423412343
  667. MAKE_PCWSTR(curAsmInfo.m_sbComponentIdentifier),
  668. MAKE_PCWSTR(ShortLongPair))); // a.dll | a.dll
  669. //
  670. // add this file to the cabinet
  671. //
  672. IFFAILED_EXIT(AddFileToCabinetW(
  673. curAsmInfo.m_sbAssemblyPath, CchFullpathFilename,
  674. curAsmInfo.m_sbAssemblyPath + curAsmInfo.m_CchAssemblyPath, curAsmInfo.m_sbAssemblyPath.Cch() - curAsmInfo.m_CchAssemblyPath));
  675. //
  676. // set Component Table with ComponentID, componentIdentifier, keypath:
  677. //
  678. if (curAsmInfo.m_fComponentTableSet == FALSE)
  679. {
  680. IFFAILED_EXIT(SetComponentId(curAsmInfo.m_sbComponentIdentifier, curAsmInfo.m_sbAssemblyPath + curAsmInfo.m_CchAssemblyPath));
  681. curAsmInfo.m_fComponentTableSet = TRUE;
  682. }
  683. Exit:
  684. if (pattrs)
  685. pattrs->Release();
  686. if(pChild)
  687. pChild->Release();
  688. return hr;
  689. }
  690. BOOL IsValidAttributes(const ELEMENT_ALLOWED_ATTRIBUTE attribs[], DWORD num)
  691. {
  692. for (DWORD i=0; i< num; i++)
  693. {
  694. if (attribs[i].m_fRequired && ! attribs[i].m_fValued)
  695. {
  696. ::SetLastError(ERROR_INVALID_DATA);
  697. return FALSE;
  698. }
  699. }
  700. return TRUE;
  701. }
  702. HRESULT GetPrimAssemblyName(PCWSTR pwszAssemblyName, PWSTR pwszPrimAssemblyName, DWORD & cch)
  703. {
  704. HRESULT hr = S_OK;
  705. DWORD i = 0, num = wcslen(pwszAssemblyName);
  706. if (cch < num)
  707. {
  708. cch = num;
  709. SET_HRERR_AND_EXIT(ERROR_INSUFFICIENT_BUFFER);
  710. }
  711. wcscpy(pwszPrimAssemblyName, pwszAssemblyName);
  712. while ( i < num)
  713. {
  714. if (pwszPrimAssemblyName[i] == L'-')
  715. {
  716. pwszPrimAssemblyName[i] = L'_';
  717. }
  718. i++;
  719. }
  720. Exit:
  721. return hr;
  722. }
  723. HRESULT MSM_PARSER_DOM_NODE_assemblyIdentity(IXMLDOMNode* node)
  724. {
  725. //
  726. // we only are interested in the assemblyIdentity of the component, that is,
  727. // <assemblyIdentity .... /> at the head of manifest, ignore <assemblyIdentity ..../> of
  728. // dependency
  729. //
  730. if (curAsmInfo.m_sbComponentIdentifier.IsEmpty() == FALSE)
  731. {
  732. return S_OK;
  733. }
  734. HRESULT hr = S_OK;
  735. static CSmallStringBuffer rg_StringBuffer[NUM_OF_ALLOWED_ATTRIBUTE_ASSEMBLYIDENTITY];
  736. static ELEMENT_ALLOWED_ATTRIBUTE rg_assemblyIdentity_AllowedAttributes[NUM_OF_ALLOWED_ATTRIBUTE_ASSEMBLYIDENTITY] =
  737. {
  738. {L"name", TRUE, NULL, FALSE, &rg_StringBuffer[0]},
  739. {L"language", FALSE, NULL, FALSE, &rg_StringBuffer[1]},
  740. {L"version", TRUE, NULL, FALSE, &rg_StringBuffer[2]},
  741. {L"processorArchitecture", TRUE, NULL, FALSE, &rg_StringBuffer[3]},
  742. {L"publicKeyToken", FALSE, NULL, FALSE, &rg_StringBuffer[4]},
  743. {L"type", TRUE, NULL, FALSE, &rg_StringBuffer[5]}
  744. };
  745. CStringBuffer tmp;
  746. WCHAR tmpbuf[MAX_PATH];
  747. DWORD num = NUMBER_OF(tmpbuf);
  748. CurrentAssemblyReset;
  749. IFFAILED_EXIT(PropagateXMLDOMNode(node, rg_assemblyIdentity_AllowedAttributes, NUM_OF_ALLOWED_ATTRIBUTE_ASSEMBLYIDENTITY));
  750. IFFALSE_EXIT(IsValidAttributes(rg_assemblyIdentity_AllowedAttributes, NUM_OF_ALLOWED_ATTRIBUTE_ASSEMBLYIDENTITY));
  751. IFFAILED_EXIT(GetPrimAssemblyName(*rg_assemblyIdentity_AllowedAttributes[MSMGEN_ASSEMBLYIDENTTIY_ATTRIBUTE_NAME].m_value, tmpbuf, num));
  752. //
  753. // Set module identifier
  754. //
  755. IFFALSE_EXIT(g_MsmInfo.m_sbModuleIdentifier.Win32Assign(tmpbuf, wcslen(tmpbuf)));
  756. IFFALSE_EXIT(g_MsmInfo.m_sbModuleIdentifier.Win32Append(g_MsmInfo.m_sbModuleGuidStr));
  757. //
  758. // set componentIdentifier and add entries to table which depends on componentIdentifier
  759. //
  760. IFFALSE_EXIT(curAsmInfo.m_sbComponentIdentifier.Win32Assign(tmpbuf, wcslen(tmpbuf)));
  761. IFFALSE_EXIT(curAsmInfo.m_sbComponentIdentifier.Win32Append(g_MsmInfo.m_sbModuleGuidStr));
  762. //
  763. // insert manifest & catalog into File Table, cabinet,
  764. //
  765. IFFAILED_EXIT(SetManifestAndCatalog());
  766. //
  767. // write MsiAssemblyName table
  768. //
  769. for (DWORD i = 0; i < NUMBER_OF(rg_assemblyIdentity_AllowedAttributes); i++)
  770. {
  771. if (rg_assemblyIdentity_AllowedAttributes[i].m_fValued)
  772. {
  773. IFFAILED_EXIT(ExecuteInsertTableSQL(OPT_MSIASSEMBLYNAME,
  774. NUMBER_OF_PARAM_TO_INSERT_TABLE_MSIASSEMBLYNAME,
  775. MAKE_PCWSTR(curAsmInfo.m_sbComponentIdentifier),
  776. MAKE_PCWSTR(rg_assemblyIdentity_AllowedAttributes[i].m_name),
  777. MAKE_PCWSTR(*rg_assemblyIdentity_AllowedAttributes[i].m_value)));
  778. }
  779. }
  780. //
  781. // write MsiAssebly Table
  782. //
  783. curAsmInfo.m_sbManifestFileName.Left(curAsmInfo.m_CchManifestFileName);
  784. IFFALSE_EXIT(curAsmInfo.m_sbManifestFileName.Win32Append(g_MsmInfo.m_sbModuleGuidStr));
  785. IFFAILED_EXIT(ExecuteInsertTableSQL(
  786. OPT_MSIASSEMBLY,
  787. NUMBER_OF_PARAM_TO_INSERT_TABLE_MSIASSEMBLY,
  788. MAKE_PCWSTR(curAsmInfo.m_sbComponentIdentifier),
  789. MAKE_PCWSTR(GUID_NULL_IN_STRING),
  790. MAKE_PCWSTR(curAsmInfo.m_sbManifestFileName))); // sfp.manifest.12343454534534534
  791. //
  792. // write ModuleSiguature table using version
  793. //
  794. BOOL fExist;
  795. IFFAILED_EXIT(ExecuteQuerySQL(L"ModuleSignature", L"ModuleID", g_MsmInfo.m_sbModuleIdentifier, fExist, NULL));
  796. if ( fExist == FALSE)
  797. {
  798. IFFAILED_EXIT(ExecuteInsertTableSQL(OPT_MODULESIGNATURE,
  799. NUMBER_OF_PARAM_TO_INSERT_TABLE_MODULESIGNATURE,
  800. MAKE_PCWSTR(g_MsmInfo.m_sbModuleIdentifier),
  801. MAKE_PCWSTR(*rg_assemblyIdentity_AllowedAttributes[MSMGEN_ASSEMBLYIDENTTIY_ATTRIBUTE_VERSION].m_value)));
  802. }else
  803. {
  804. // updateRecord
  805. }
  806. //
  807. // write ModuleComponent table using version
  808. //
  809. IFFAILED_EXIT(ExecuteQuerySQL(L"ModuleComponents", L"Component", curAsmInfo.m_sbComponentIdentifier, fExist, NULL));
  810. if ( fExist == FALSE)
  811. {
  812. IFFAILED_EXIT(ExecuteInsertTableSQL(OPT_MODULECOMPONENTS,
  813. NUMBER_OF_PARAM_TO_INSERT_TABLE_MODULECOMPONENTS,
  814. MAKE_PCWSTR(curAsmInfo.m_sbComponentIdentifier),
  815. MAKE_PCWSTR(g_MsmInfo.m_sbModuleIdentifier)));
  816. }else
  817. {
  818. // updateRecord
  819. }
  820. Exit:
  821. return hr;
  822. }
  823. HRESULT MSM_PARSER_DOM_NODE_comClass(IXMLDOMNode* node)
  824. {
  825. HRESULT hr = S_OK;
  826. // About this array :
  827. // 0, 2 would be stored in class table
  828. // 1 would be stored in progid table
  829. // 3 would be ignored and Typelib Table would be created when "<typelib />" is encounter
  830. // 4 would be ignored
  831. //
  832. static CSmallStringBuffer rg_StringBuffer[NUM_OF_ALLOWED_ATTRIBUTE_COMCLASS];
  833. static ELEMENT_ALLOWED_ATTRIBUTE rg_comClass_AllowedAttributes[NUM_OF_ALLOWED_ATTRIBUTE_COMCLASS] = {
  834. {L"clsid", TRUE, NULL, FALSE, &rg_StringBuffer[0]},
  835. {L"description", FALSE, NULL, FALSE, &rg_StringBuffer[1]},
  836. {L"progid", FALSE, NULL, FALSE, &rg_StringBuffer[2]},
  837. {L"tlbid", FALSE, NULL, FALSE, &rg_StringBuffer[3]},
  838. {L"threadingModel", FALSE, NULL, FALSE, &rg_StringBuffer[4]}
  839. };
  840. CurrentAssemblyReset;
  841. IFFAILED_EXIT(PropagateXMLDOMNode(node, rg_comClass_AllowedAttributes, NUM_OF_ALLOWED_ATTRIBUTE_COMCLASS));
  842. IFFALSE_EXIT(IsValidAttributes(rg_comClass_AllowedAttributes, NUM_OF_ALLOWED_ATTRIBUTE_COMCLASS));
  843. //
  844. // if the progId is not NULL, Insert an entry to ProgID Table
  845. //
  846. if (rg_comClass_AllowedAttributes[MSMGEN_COMCLASS_ATTRIBUTE_PROGID].m_fValued)
  847. {
  848. IFFAILED_EXIT(ExecuteInsertTableSQL(
  849. OPT_PROGID,
  850. NUMBER_OF_PARAM_TO_INSERT_TABLE_PROGID,
  851. MAKE_PCWSTR(*rg_comClass_AllowedAttributes[MSMGEN_COMCLASS_ATTRIBUTE_PROGID].m_value),
  852. MAKE_PCWSTR(*rg_comClass_AllowedAttributes[MSMGEN_COMCLASS_ATTRIBUTE_CLSID].m_value),
  853. MAKE_PCWSTR(*rg_comClass_AllowedAttributes[MSMGEN_COMCLASS_ATTRIBUTE_DESCRIPTION].m_value)));
  854. }
  855. //
  856. // insert one entry to ClassTable
  857. //
  858. IFFAILED_EXIT(ExecuteInsertTableSQL(
  859. OPT_CLASS,
  860. NUMBER_OF_PARAM_TO_INSERT_TABLE_CLASS,
  861. MAKE_PCWSTR(*rg_comClass_AllowedAttributes[MSMGEN_COMCLASS_ATTRIBUTE_CLSID].m_value),
  862. MAKE_PCWSTR(curAsmInfo.m_sbComponentIdentifier),
  863. MAKE_PCWSTR(*rg_comClass_AllowedAttributes[MSMGEN_COMCLASS_ATTRIBUTE_PROGID].m_value),
  864. MAKE_PCWSTR(*rg_comClass_AllowedAttributes[MSMGEN_COMCLASS_ATTRIBUTE_DESCRIPTION].m_value),
  865. MAKE_PCWSTR(GUID_NULL_IN_STRING)));
  866. Exit:
  867. return hr;
  868. }
  869. HRESULT MSM_PARSER_DOM_NODE_typelib(IXMLDOMNode* node)
  870. {
  871. HRESULT hr = S_OK;
  872. //
  873. // all of three attributes are required for "<typelib .... />" element
  874. //
  875. static CSmallStringBuffer rg_StringBuffer[NUM_OF_ALLOWED_ATTRIBUTE_TYPELIB];
  876. static ELEMENT_ALLOWED_ATTRIBUTE rg_typelib_AllowedAttributes[NUM_OF_ALLOWED_ATTRIBUTE_TYPELIB] = {
  877. {L"tlbid", TRUE, NULL, FALSE, &rg_StringBuffer[0]},
  878. {L"version", TRUE, NULL, FALSE, &rg_StringBuffer[1]},
  879. {L"helpdir", TRUE, NULL, FALSE, &rg_StringBuffer[2]}
  880. };
  881. CurrentAssemblyReset;
  882. IFFAILED_EXIT(PropagateXMLDOMNode(node, rg_typelib_AllowedAttributes, NUM_OF_ALLOWED_ATTRIBUTE_TYPELIB));
  883. IFFALSE_EXIT(IsValidAttributes(rg_typelib_AllowedAttributes, NUM_OF_ALLOWED_ATTRIBUTE_TYPELIB));
  884. //
  885. // insert one entry to class table
  886. //
  887. IFFAILED_EXIT(ExecuteInsertTableSQL(
  888. OPT_TYPELIB,
  889. NUMBER_OF_PARAM_TO_INSERT_TABLE_TYPELIB,
  890. MAKE_PCWSTR(*rg_typelib_AllowedAttributes[MSMGEN_TYPELIB_ATTRIBUTE_TLBID].m_value),
  891. MAKE_PCWSTR(curAsmInfo.m_sbComponentIdentifier),
  892. MAKE_PCWSTR(*rg_typelib_AllowedAttributes[MSMGEN_TYPELIB_ATTRIBUTE_VERSION].m_value),
  893. MAKE_PCWSTR(GUID_NULL_IN_STRING)));
  894. Exit:
  895. return hr;
  896. }
  897. HRESULT InsertCabinetIntoMsm()
  898. {
  899. HRESULT hr = S_OK;
  900. PMSIHANDLE hView = NULL;
  901. PMSIHANDLE hRec = NULL;
  902. CurrentAssemblyReset;
  903. IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiDatabaseOpenViewA(g_MsmInfo.m_hdb, "INSERT INTO `_Streams` (`Name`, `Data`) VALUES (?, ?)", &hView));
  904. hRec = ::MsiCreateRecord(2);
  905. if (NULL == hRec)
  906. SETFAIL_AND_EXIT;
  907. IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiRecordSetStringW(hRec, 1, MERGEMODULE_CABINET_FILENAME));
  908. IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiRecordSetStreamW(hRec, 2, g_MsmInfo.m_sbCabinet));
  909. IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiViewExecute(hView, hRec));
  910. IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiViewClose(hView));
  911. Exit:
  912. return hr;
  913. }
  914. //
  915. // each entry in Component Table always need a KeyPath, which is a datafile
  916. // for some assembly, which has no datafile or policy assembly, we have to add an entry to ComponentTable at the end
  917. // of the generation
  918. //
  919. HRESULT CheckComponentTable()
  920. {
  921. HRESULT hr = S_OK;
  922. if (curAsmInfo.m_fComponentTableSet == FALSE)
  923. {
  924. IFFAILED_EXIT(SetComponentId(curAsmInfo.m_sbComponentIdentifier, NULL));
  925. curAsmInfo.m_fComponentTableSet = TRUE;
  926. }
  927. Exit:
  928. return hr;
  929. }