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.

819 lines
25 KiB

  1. // --------------------------------------------------------------------------------
  2. // Exploder.cpp
  3. // --------------------------------------------------------------------------------
  4. #include "pch.hxx"
  5. #include "resource.h"
  6. // --------------------------------------------------------------------------------
  7. // Constants
  8. // --------------------------------------------------------------------------------
  9. #define CCHMAX_RES 1024
  10. #define CCHMAX_PATH_EXPLODER 1024
  11. // --------------------------------------------------------------------------------
  12. // String Consts
  13. // --------------------------------------------------------------------------------
  14. static const char c_szRegCmd[] = "/reg";
  15. static const char c_szUnRegCmd[] = "/unreg";
  16. static const char c_szReg[] = "Reg";
  17. static const char c_szUnReg[] = "UnReg";
  18. static const char c_szAdvPackDll[] = "ADVPACK.DLL";
  19. static const char c_szSource[] = "/SOURCE:";
  20. static const char c_szDest[] = "/DEST:";
  21. // --------------------------------------------------------------------------------
  22. // Globals
  23. // --------------------------------------------------------------------------------
  24. HINSTANCE g_hInst=NULL;
  25. CHAR g_szTitle[CCHMAX_RES];
  26. IMalloc *g_pMalloc=NULL;
  27. // --------------------------------------------------------------------------------
  28. // BODYFILEINFO
  29. // --------------------------------------------------------------------------------
  30. typedef struct tagBODYFILEINFO {
  31. HBODY hBody;
  32. LPSTR pszCntId;
  33. LPSTR pszCntLoc;
  34. LPSTR pszFileName;
  35. LPSTR pszFilePath;
  36. BYTE fIsHtml;
  37. IStream *pStmFile;
  38. } BODYFILEINFO, *LPBODYFILEINFO;
  39. // --------------------------------------------------------------------------------
  40. // Prototypes
  41. // --------------------------------------------------------------------------------
  42. HRESULT CallRegInstall(LPCSTR szSection);
  43. HRESULT ReplaceContentIds(LPSTREAM pStmHtml, LPBODYFILEINFO prgBody, DWORD cBodies);
  44. int WinMainT(HINSTANCE hInst, HINSTANCE hInstPrev, LPTSTR pszCmdLine, int nCmdShow);
  45. HRESULT MimeOleExplodeMhtmlFile(LPCSTR pszSrcFile, LPSTR pszDstDir, INT *pnError);
  46. // --------------------------------------------------------------------------------
  47. // IF_FAILEXIT_ERROR
  48. // --------------------------------------------------------------------------------
  49. #define IF_FAILEXIT_ERROR(_nError, hrExp) \
  50. if (FAILED(hrExp)) { \
  51. TraceResult(hr); \
  52. *pnError = _nError; \
  53. goto exit; \
  54. } else
  55. // --------------------------------------------------------------------------------
  56. // ModuleEntry - Stolen from the CRT, used to shirink our code
  57. // --------------------------------------------------------------------------------
  58. int _stdcall ModuleEntry(void)
  59. {
  60. // Locals
  61. int i;
  62. STARTUPINFOA si;
  63. LPTSTR pszCmdLine;
  64. // Get Malloc
  65. CoGetMalloc(1, &g_pMalloc);
  66. // Get the command line
  67. pszCmdLine = GetCommandLine();
  68. // We don't want the "No disk in drive X:" requesters, so we set the critical error mask such that calls will just silently fail
  69. SetErrorMode(SEM_FAILCRITICALERRORS);
  70. // Parse the command line
  71. if (*pszCmdLine == TEXT('\"'))
  72. {
  73. // Scan, and skip over, subsequent characters until another double-quote or a null is encountered.
  74. while ( *++pszCmdLine && (*pszCmdLine != TEXT('\"')))
  75. {};
  76. // If we stopped on a double-quote (usual case), skip over it.
  77. if (*pszCmdLine == TEXT('\"'))
  78. pszCmdLine++;
  79. }
  80. else
  81. {
  82. while (*pszCmdLine > TEXT(' '))
  83. pszCmdLine++;
  84. }
  85. // Skip past any white space preceeding the second token.
  86. while (*pszCmdLine && (*pszCmdLine <= TEXT(' ')))
  87. pszCmdLine++;
  88. // Register
  89. if (0 == lstrcmpi(c_szRegCmd, pszCmdLine))
  90. {
  91. CallRegInstall(c_szReg);
  92. goto exit;
  93. }
  94. // Unregister
  95. else if (0 == lstrcmpi(c_szUnRegCmd, pszCmdLine))
  96. {
  97. CallRegInstall(c_szUnReg);
  98. goto exit;
  99. }
  100. // Get startup information...
  101. si.dwFlags = 0;
  102. GetStartupInfoA(&si);
  103. // Call the real winmain
  104. i = WinMainT(GetModuleHandle(NULL), NULL, pszCmdLine, si.dwFlags & STARTF_USESHOWWINDOW ? si.wShowWindow : SW_SHOWDEFAULT);
  105. exit:
  106. // Cleanup
  107. SafeRelease(g_pMalloc);
  108. // Since we now have a way for an extension to tell us when it is finished, we will terminate all processes when the main thread goes away.
  109. ExitProcess(i);
  110. // Done
  111. return i;
  112. }
  113. // --------------------------------------------------------------------------------
  114. // WinMainT
  115. // --------------------------------------------------------------------------------
  116. int WinMainT(HINSTANCE hInst, HINSTANCE hInstPrev, LPTSTR pszCmdLine, int nCmdShow)
  117. {
  118. // Locals
  119. HRESULT hr;
  120. CHAR szRes[CCHMAX_RES];
  121. CHAR szSource[CCHMAX_PATH_EXPLODER];
  122. CHAR szDest[CCHMAX_PATH_EXPLODER];
  123. LPSTR pszT;
  124. DWORD i;
  125. INT nError;
  126. // Message
  127. LoadString(hInst, IDS_TITLE, g_szTitle, ARRAYSIZE(g_szTitle));
  128. // Message
  129. LoadString(hInst, IDS_HELP, szRes, ARRAYSIZE(szRes));
  130. // If Command Line is Empty...
  131. if (NULL == pszCmdLine || StrStrA(pszCmdLine, szRes) || *pszCmdLine == '?' || lstrcmpi("\\?", pszCmdLine) == 0)
  132. {
  133. // Message
  134. LoadString(hInst, IDS_CMDLINE_FORMAT, szRes, ARRAYSIZE(szRes));
  135. // Message
  136. MessageBox(NULL, szRes, g_szTitle, MB_OK | MB_ICONINFORMATION);
  137. // Done
  138. goto exit;
  139. }
  140. // Null Out Source and Dest
  141. *szSource = '\0';
  142. *szDest = '\0';
  143. // If pszCmdLine specifies a specific, existing file...
  144. if (PathFileExists(pszCmdLine))
  145. {
  146. // Copy To source
  147. lstrcpyn(szSource, pszCmdLine, ARRAYSIZE(szSource));
  148. // Pick a Temporary Location to store the thicket
  149. GetTempPath(ARRAYSIZE(szDest), szDest);
  150. }
  151. // Otherwise, try to get a source
  152. else
  153. {
  154. // Lets Upper Case the Command Line
  155. CharUpper(pszCmdLine);
  156. // Try to locate /SOURCE:
  157. pszT = StrStrA(pszCmdLine, c_szSource);
  158. // If we found /SOURCE, then read the contents...
  159. if (pszT)
  160. {
  161. // Step over /SOURCE:
  162. pszT += lstrlen(c_szSource);
  163. // Initialize
  164. i = 0;
  165. // Read into szSource, until I hit a / or end of string...
  166. while ('\0' != *pszT && '/' != *pszT && i < CCHMAX_PATH_EXPLODER)
  167. szSource[i++] = *pszT++;
  168. // Pound in a Null
  169. szSource[i] = '\0';
  170. // Strip Leading and Trailing Whitespace
  171. UlStripWhitespace(szSource, TRUE, TRUE, NULL);
  172. // See if file exists
  173. if (FALSE == PathFileExists(szSource))
  174. {
  175. // Locals
  176. CHAR szError[CCHMAX_RES + CCHMAX_PATH_EXPLODER];
  177. // Message
  178. LoadString(hInst, IDS_FILE_NOEXIST, szRes, ARRAYSIZE(szRes));
  179. // Format the error message
  180. wsprintf(szError, szRes, szSource);
  181. // Message
  182. INT nAnswer = MessageBox(NULL, szError, g_szTitle, MB_YESNO | MB_ICONEXCLAMATION );
  183. // Done
  184. if (IDNO == nAnswer)
  185. goto exit;
  186. // Otherwise, clear szSource
  187. *szSource = '\0';
  188. }
  189. }
  190. // No Source File, lets browser for one
  191. if (FIsEmptyA(szSource))
  192. {
  193. // Locals
  194. OPENFILENAME ofn;
  195. CHAR rgszFilter[CCHMAX_PATH_EXPLODER];
  196. CHAR szDir[MAX_PATH];
  197. // Copy in the source of exploder.exe
  198. GetModuleFileName(hInst, szDir, ARRAYSIZE(szDir));
  199. // Initialize szDest
  200. PathRemoveFileSpecA(szDir);
  201. // Initialize ofn
  202. ZeroMemory(&ofn, sizeof(OPENFILENAME));
  203. // Initialize the STring
  204. *szSource ='\0';
  205. // Load the MHTML File Filter
  206. LoadString(hInst, IDS_MHTML_FILTER, rgszFilter, ARRAYSIZE(rgszFilter));
  207. // Fixup the String
  208. ReplaceChars(rgszFilter, '|', '\0');
  209. // Initialize the Open File Structure
  210. ofn.lStructSize = sizeof(OPENFILENAME);
  211. ofn.hwndOwner = NULL;
  212. ofn.hInstance = hInst;
  213. ofn.lpstrFilter = rgszFilter;
  214. ofn.nFilterIndex = 1;
  215. ofn.lpstrFile = szSource;
  216. ofn.nMaxFile = CCHMAX_PATH_EXPLODER;
  217. ofn.lpstrInitialDir = szDir;
  218. ofn.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR;
  219. // Get Open File Name
  220. if (FALSE == GetOpenFileName(&ofn))
  221. goto exit;
  222. }
  223. }
  224. // Do we have a valid destination...
  225. if (FALSE == PathIsDirectoryA(szDest))
  226. {
  227. // Try to locate /DEST:
  228. pszT = StrStrA(pszCmdLine, c_szDest);
  229. // If we found /DEST, then read the contents...
  230. if (pszT)
  231. {
  232. // Step over /DEST:
  233. pszT += lstrlen(c_szDest);
  234. // Initialize
  235. i = 0;
  236. // Read into szSource, until I hit a / or end of string...
  237. while ('\0' != *pszT && '/' != *pszT && i < CCHMAX_PATH_EXPLODER)
  238. szDest[i++] = *pszT++;
  239. // Pound in a Null
  240. szDest[i] = '\0';
  241. // Strip Leading and Trailing Whitespace
  242. UlStripWhitespace(szDest, TRUE, TRUE, NULL);
  243. // See if file exists
  244. if (FALSE == PathIsDirectoryA(szDest))
  245. {
  246. // Locals
  247. CHAR szError[CCHMAX_RES + CCHMAX_PATH_EXPLODER];
  248. // Message
  249. LoadString(hInst, IDS_DIRECTORY_NOEXIST, szRes, ARRAYSIZE(szRes));
  250. // Format the error message
  251. wsprintf(szError, szRes, szDest);
  252. // Message
  253. INT nAnswer = MessageBox(NULL, szError, g_szTitle, MB_YESNO | MB_ICONEXCLAMATION );
  254. // Done
  255. if (IDNO == nAnswer)
  256. goto exit;
  257. // Try to create the directory
  258. if (FALSE == CreateDirectory(szDest, NULL))
  259. {
  260. // Message
  261. LoadString(hInst, IDS_NOCREATE_DIRECTORY, szRes, ARRAYSIZE(szRes));
  262. // Format the error message
  263. wsprintf(szError, szRes, szDest);
  264. // Message
  265. INT nAnswer = MessageBox(NULL, szError, g_szTitle, MB_YESNO | MB_ICONEXCLAMATION );
  266. // Done
  267. if (IDNO == nAnswer)
  268. goto exit;
  269. // Clear *szDest
  270. *szDest = '\0';
  271. }
  272. }
  273. }
  274. // No Source File, lets browser for one
  275. if (FIsEmptyA(szDest))
  276. {
  277. // Copy in the source of exploder.exe
  278. GetModuleFileName(hInst, szDest, ARRAYSIZE(szDest));
  279. // Initialize szDest
  280. PathRemoveFileSpecA(szDest);
  281. // Failure
  282. if (FALSE == BrowseForFolder(hInst, NULL, szDest, ARRAYSIZE(szDest), IDS_BROWSE_DEST, TRUE))
  283. goto exit;
  284. // Better be a directory
  285. Assert(PathIsDirectoryA(szDest));
  286. }
  287. }
  288. // Validate the dest and source
  289. Assert(PathIsDirectoryA(szDest) && PathFileExists(szSource));
  290. // Explode the file
  291. nError = 0;
  292. hr = MimeOleExplodeMhtmlFile(szSource, szDest, &nError);
  293. // Failure ?
  294. if (FAILED(hr) || 0 != nError)
  295. {
  296. // Locals
  297. CHAR szError[CCHMAX_RES + CCHMAX_PATH_EXPLODER];
  298. // Message
  299. LoadString(hInst, nError, szRes, ARRAYSIZE(szRes));
  300. // Need to format with file name ?
  301. if (IDS_OPEN_FILE == nError || IDS_LOAD_FAILURE == nError || IDS_NO_HTML == nError)
  302. {
  303. // Format the error message
  304. wsprintf(szError, szRes, szSource, hr);
  305. }
  306. // Otherwise,
  307. else
  308. {
  309. // Format the error message
  310. wsprintf(szError, szRes, hr);
  311. }
  312. // Message
  313. MessageBox(NULL, szError, g_szTitle, MB_OK | MB_ICONEXCLAMATION);
  314. }
  315. exit:
  316. // Done
  317. return(1);
  318. }
  319. // --------------------------------------------------------------------------------
  320. // MimeOleExplodeMhtmlFile
  321. // --------------------------------------------------------------------------------
  322. HRESULT MimeOleExplodeMhtmlFile(LPCSTR pszSrcFile, LPSTR pszDstDir, INT *pnError)
  323. {
  324. // Locals
  325. HRESULT hr=S_OK;
  326. IStream *pStmFile=NULL;
  327. IMimeMessage *pMessage=NULL;
  328. HBODY hRootHtml=NULL;
  329. DWORD cMaxBodies;
  330. DWORD cBodies=0;
  331. FINDBODY FindBody={0};
  332. DWORD cchDstDir;
  333. DWORD iRootBody=0xffffffff;
  334. HBODY hBody;
  335. PROPVARIANT Variant;
  336. SHELLEXECUTEINFO ExecuteInfo;
  337. LPBODYFILEINFO prgBody=NULL;
  338. LPBODYFILEINFO pInfo;
  339. DWORD i;
  340. IMimeBody *pBody=NULL;
  341. // Trace
  342. TraceCall("MimeOleExplodeMhtmlFile");
  343. // Invalid Args
  344. if (FALSE == PathIsDirectoryA(pszDstDir) || FALSE == PathFileExists(pszSrcFile) || NULL == pnError)
  345. return TraceResult(E_INVALIDARG);
  346. // Initialize
  347. *pnError = 0;
  348. // Get DstDir Length
  349. cchDstDir = lstrlen(pszDstDir);
  350. // Remove last \\ from pszDstDir
  351. if (cchDstDir && pszDstDir[cchDstDir - 1] == '\\')
  352. {
  353. pszDstDir[cchDstDir - 1] = '\0';
  354. cchDstDir--;
  355. }
  356. // Create a Mime Message
  357. IF_FAILEXIT_ERROR(IDS_MEMORY, hr = MimeOleCreateMessage(NULL, &pMessage));
  358. // Initialize the message
  359. IF_FAILEXIT_ERROR(IDS_GENERAL_ERROR, hr = pMessage->InitNew());
  360. // Create a stream on the file
  361. IF_FAILEXIT_ERROR(IDS_OPEN_FILE, hr = OpenFileStream((LPSTR)pszSrcFile, OPEN_EXISTING, GENERIC_READ, &pStmFile));
  362. // Load the Message
  363. IF_FAILEXIT_ERROR(IDS_LOAD_FAILURE, hr = pMessage->Load(pStmFile));
  364. // Invalid Message
  365. if (MIME_S_INVALID_MESSAGE == hr)
  366. {
  367. *pnError = IDS_LOAD_FAILURE;
  368. goto exit;
  369. }
  370. // Count the Bodies
  371. IF_FAILEXIT(hr = pMessage->CountBodies(NULL, TRUE, &cMaxBodies));
  372. // Allocate
  373. IF_FAILEXIT_ERROR(IDS_MEMORY, hr = HrAlloc((LPVOID *)&prgBody, sizeof(BODYFILEINFO) * cMaxBodies));
  374. // Zero
  375. ZeroMemory(prgBody, sizeof(BODYFILEINFO) * cMaxBodies);
  376. // Get the root body...
  377. IF_FAILEXIT_ERROR(IDS_NO_HTML, hr = pMessage->GetTextBody(TXT_HTML, IET_DECODED, NULL, &hRootHtml));
  378. // Loop through all the bodies
  379. hr = pMessage->FindFirst(&FindBody, &hBody);
  380. // Loop
  381. while(SUCCEEDED(hr))
  382. {
  383. // Must have an hBody
  384. Assert(hBody);
  385. // Skip Multipart Bodies
  386. if (S_FALSE == pMessage->IsContentType(hBody, STR_CNT_MULTIPART, NULL))
  387. {
  388. // Is this the root ?
  389. if (hBody == hRootHtml)
  390. iRootBody = cBodies;
  391. // Readability
  392. pInfo = &prgBody[cBodies];
  393. // Better not over run prgBody
  394. pInfo->hBody = hBody;
  395. // Init the Variant
  396. Variant.vt = VT_LPSTR;
  397. // Get the Content Id
  398. if (SUCCEEDED(pMessage->GetBodyProp(hBody, PIDTOSTR(PID_HDR_CNTID), 0, &Variant)))
  399. pInfo->pszCntId = Variant.pszVal;
  400. // Get the Content Location
  401. if (SUCCEEDED(pMessage->GetBodyProp(hBody, PIDTOSTR(PID_HDR_CNTLOC), 0, &Variant)))
  402. pInfo->pszCntLoc = Variant.pszVal;
  403. // Generate a filename
  404. if (SUCCEEDED(pMessage->GetBodyProp(hBody, PIDTOSTR(PID_ATT_GENFNAME), 0, &Variant)))
  405. pInfo->pszFileName = Variant.pszVal;
  406. // If its html, lets make sure that the filename has a .html file extension
  407. pInfo->fIsHtml = (S_OK == pMessage->IsContentType(hBody, STR_CNT_TEXT, STR_SUB_HTML)) ? TRUE : FALSE;
  408. // Take the filename and build the file path
  409. Assert(pInfo->pszFileName);
  410. // Don't Crash
  411. if (NULL == pInfo->pszFileName)
  412. {
  413. hr = TraceResult(E_UNEXPECTED);
  414. goto exit;
  415. }
  416. // Validate Extension
  417. if (pInfo->fIsHtml)
  418. {
  419. // Get Extension
  420. LPSTR pszExt = PathFindExtensionA(pInfo->pszFileName);
  421. // If Null or not .html..
  422. if (NULL == pszExt || lstrcmpi(pszExt, ".html") != 0)
  423. {
  424. // Re-allocate pInfo->pszFileName...
  425. IF_FAILEXIT_ERROR(IDS_MEMORY, hr = HrRealloc((LPVOID *)&pInfo->pszFileName, lstrlen(pInfo->pszFileName) + 10));
  426. // Rename the Extension
  427. PathRenameExtensionA(pInfo->pszFileName, ".html");
  428. }
  429. }
  430. // Build that full file path
  431. IF_FAILEXIT_ERROR(IDS_MEMORY, hr = HrAlloc((LPVOID *)&pInfo->pszFilePath, lstrlen(pszDstDir) + lstrlen(pInfo->pszFileName) + 10));
  432. // Formath the filepath
  433. wsprintf(pInfo->pszFilePath, "%s\\%s", pszDstDir, pInfo->pszFileName);
  434. // Save the body to the file
  435. IF_FAILEXIT(hr = pMessage->BindToObject(hBody, IID_IMimeBody, (LPVOID *)&pBody));
  436. // Save to the file
  437. IF_FAILEXIT(hr = pBody->SaveToFile(IET_DECODED, pInfo->pszFilePath));
  438. // Open a file stream
  439. if (pInfo->fIsHtml)
  440. {
  441. // Open it if its html
  442. IF_FAILEXIT(hr = OpenFileStream(pInfo->pszFilePath, OPEN_ALWAYS, GENERIC_READ | GENERIC_WRITE, &pInfo->pStmFile));
  443. }
  444. // Increment cBodies
  445. cBodies++;
  446. }
  447. // Loop through all the bodies
  448. hr = pMessage->FindNext(&FindBody, &hBody);
  449. }
  450. // Reset hr
  451. hr = S_OK;
  452. // Root Body was not found
  453. Assert(iRootBody != 0xffffffff);
  454. // Bad News
  455. if (0xffffffff == iRootBody)
  456. {
  457. hr = TraceResult(E_UNEXPECTED);
  458. goto exit;
  459. }
  460. // Walk through and fixup all HTML files and close all streams
  461. for (i=0; i<cBodies; i++)
  462. {
  463. // Readability
  464. pInfo = &prgBody[i];
  465. // If HTML...
  466. if (pInfo->fIsHtml)
  467. {
  468. // Better have an open stream
  469. Assert(pInfo->pStmFile);
  470. // Failure
  471. if (NULL == pInfo->pStmFile)
  472. {
  473. hr = TraceResult(E_UNEXPECTED);
  474. goto exit;
  475. }
  476. // Replace all the CID references with file references...
  477. ReplaceContentIds(pInfo->pStmFile, prgBody, cBodies);
  478. }
  479. // Release this stream
  480. SafeRelease(pInfo->pStmFile);
  481. }
  482. // Launch the Currently Registered HTML Editor ontop of iRootBody pszFilePath
  483. ZeroMemory(&ExecuteInfo, sizeof(SHELLEXECUTEINFO));
  484. ExecuteInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
  485. ExecuteInfo.cbSize = sizeof(SHELLEXECUTEINFO);
  486. ExecuteInfo.lpVerb = "Edit";
  487. ExecuteInfo.lpFile = prgBody[iRootBody].pszFilePath;
  488. ExecuteInfo.lpParameters = NULL;
  489. ExecuteInfo.lpDirectory = pszDstDir;
  490. ExecuteInfo.nShow = SW_SHOWNORMAL;
  491. // Compress szBlobFile
  492. ShellExecuteEx(&ExecuteInfo);
  493. exit:
  494. // General Error
  495. if (FAILED(hr) && 0 == *pnError)
  496. *pnError = IDS_GENERAL_ERROR;
  497. // Free prgBody
  498. if (prgBody)
  499. {
  500. // Loop
  501. for (i=0; i<cBodies; i++)
  502. {
  503. SafeMemFree(prgBody[i].pszCntId);
  504. SafeMemFree(prgBody[i].pszCntLoc);
  505. SafeMemFree(prgBody[i].pszFileName);
  506. SafeMemFree(prgBody[i].pszFilePath);
  507. SafeRelease(prgBody[i].pStmFile);
  508. }
  509. // Free the Array
  510. CoTaskMemFree(prgBody);
  511. }
  512. // Cleanup
  513. SafeRelease(pStmFile);
  514. SafeRelease(pBody);
  515. SafeRelease(pMessage);
  516. // Done
  517. return hr;
  518. }
  519. // --------------------------------------------------------------------------------
  520. // ReplaceContentIds
  521. // --------------------------------------------------------------------------------
  522. HRESULT ReplaceContentIds(LPSTREAM pStmHtml, LPBODYFILEINFO prgBody, DWORD cBodies)
  523. {
  524. // Locals
  525. HRESULT hr=S_OK;
  526. DWORD cb;
  527. LPSTR pszFound;
  528. LPSTR pszT;
  529. LPSTR pszHtml=NULL;
  530. LPSTR pszCntId=NULL;
  531. DWORD i;
  532. DWORD cchCntId;
  533. ULARGE_INTEGER uliSize;
  534. // Trac
  535. TraceCall("ReplaceContentIds");
  536. // Invalid Args
  537. Assert(pStmHtml && prgBody && cBodies);
  538. // Loop through the bodies
  539. for (i=0; i<cBodies; i++)
  540. {
  541. // No Content-ID here...
  542. if (NULL == prgBody[i].pszCntId)
  543. continue;
  544. // Better have a filename
  545. Assert(prgBody[i].pszFileName);
  546. // Load the stream into memory...
  547. IF_FAILEXIT(hr = HrGetStreamSize(pStmHtml, &cb));
  548. // Allocate Memory
  549. IF_FAILEXIT(hr = HrAlloc((LPVOID *)&pszHtml, cb + 1));
  550. // Rewind
  551. IF_FAILEXIT(hr = HrRewindStream(pStmHtml));
  552. // Read the Stream
  553. IF_FAILEXIT(hr = pStmHtml->Read(pszHtml, cb, NULL));
  554. // Stuff Null terminator
  555. pszHtml[cb] = '\0';
  556. // Kill pStmHtml
  557. uliSize.QuadPart = 0;
  558. IF_FAILEXIT(hr = pStmHtml->SetSize(uliSize));
  559. // Allocate Memory
  560. IF_FAILEXIT(hr = HrAlloc((LPVOID *)&pszCntId, lstrlen(prgBody[i].pszCntId) + lstrlen("cid:") + 5));
  561. // Format
  562. pszT = prgBody[i].pszCntId;
  563. if (*pszT == '<')
  564. pszT++;
  565. wsprintf(pszCntId, "cid:%s", pszT);
  566. // Remove trailing >
  567. cchCntId = lstrlen(pszCntId);
  568. if (pszCntId[cchCntId - 1] == '>')
  569. pszCntId[cchCntId - 1] = '\0';
  570. // Set pszT
  571. pszT = pszHtml;
  572. // Begin replace loop
  573. while(1)
  574. {
  575. // Find pszCntId
  576. pszFound = StrStrA(pszT, pszCntId);
  577. // Done
  578. if (NULL == pszFound)
  579. {
  580. // Write from pszT to pszFound
  581. IF_FAILEXIT(hr = pStmHtml->Write(pszT, (pszHtml + cb) - pszT, NULL));
  582. // Done
  583. break;
  584. }
  585. // Write from pszT to pszFound
  586. IF_FAILEXIT(hr = pStmHtml->Write(pszT, pszFound - pszT, NULL));
  587. // Write
  588. IF_FAILEXIT(hr = pStmHtml->Write(prgBody[i].pszFileName, lstrlen(prgBody[i].pszFileName), NULL));
  589. // Set pszT
  590. pszT = pszFound + lstrlen(pszCntId);
  591. }
  592. // Commit
  593. IF_FAILEXIT(hr = pStmHtml->Commit(STGC_DEFAULT));
  594. // Cleanup
  595. SafeMemFree(pszHtml);
  596. SafeMemFree(pszCntId);
  597. }
  598. exit:
  599. // Cleanup
  600. SafeMemFree(pszHtml);
  601. SafeMemFree(pszCntId);
  602. // Done
  603. return hr;
  604. }
  605. // --------------------------------------------------------------------------------
  606. // CallRegInstall
  607. // --------------------------------------------------------------------------------
  608. HRESULT CallRegInstall(LPCSTR szSection)
  609. {
  610. int cch;
  611. HRESULT hr;
  612. HINSTANCE hAdvPack, hinst;
  613. REGINSTALL pfnri;
  614. char szExploderDll[CCHMAX_PATH_EXPLODER], szDir[CCHMAX_PATH_EXPLODER];
  615. STRENTRY seReg[2];
  616. STRTABLE stReg;
  617. char c_szExploder[] = "EXPLODER";
  618. char c_szExploderDir[] = "EXPLODER_DIR";
  619. hr = E_FAIL;
  620. hinst = GetModuleHandle(NULL);
  621. hAdvPack = LoadLibraryA(c_szAdvPackDll);
  622. if (hAdvPack != NULL)
  623. {
  624. // Get Proc Address for registration util
  625. pfnri = (REGINSTALL)GetProcAddress(hAdvPack, achREGINSTALL);
  626. if (pfnri != NULL)
  627. {
  628. stReg.cEntries = 0;
  629. stReg.pse = seReg;
  630. GetModuleFileName(hinst, szExploderDll, ARRAYSIZE(szExploderDll));
  631. seReg[stReg.cEntries].pszName = c_szExploder;
  632. seReg[stReg.cEntries].pszValue = szExploderDll;
  633. stReg.cEntries++;
  634. lstrcpy(szDir, szExploderDll);
  635. cch = lstrlen(szDir);
  636. for ( ; cch > 0; cch--)
  637. {
  638. if (szDir[cch] == '\\')
  639. {
  640. szDir[cch] = 0;
  641. break;
  642. }
  643. }
  644. seReg[stReg.cEntries].pszName = c_szExploderDir;
  645. seReg[stReg.cEntries].pszValue = szDir;
  646. stReg.cEntries++;
  647. // Call the self-reg routine
  648. hr = pfnri(hinst, szSection, &stReg);
  649. }
  650. FreeLibrary(hAdvPack);
  651. }
  652. return(hr);
  653. }