Windows2003-3790/inetcore/outlookexpress/exploder/exploder.cpp
2020-09-30 16:53:55 +02:00

820 lines
25 KiB
C++

// --------------------------------------------------------------------------------
// Exploder.cpp
// --------------------------------------------------------------------------------
#include "pch.hxx"
#include "resource.h"
// --------------------------------------------------------------------------------
// Constants
// --------------------------------------------------------------------------------
#define CCHMAX_RES 1024
#define CCHMAX_PATH_EXPLODER 1024
// --------------------------------------------------------------------------------
// String Consts
// --------------------------------------------------------------------------------
static const char c_szRegCmd[] = "/reg";
static const char c_szUnRegCmd[] = "/unreg";
static const char c_szReg[] = "Reg";
static const char c_szUnReg[] = "UnReg";
static const char c_szAdvPackDll[] = "ADVPACK.DLL";
static const char c_szSource[] = "/SOURCE:";
static const char c_szDest[] = "/DEST:";
// --------------------------------------------------------------------------------
// Globals
// --------------------------------------------------------------------------------
HINSTANCE g_hInst=NULL;
CHAR g_szTitle[CCHMAX_RES];
IMalloc *g_pMalloc=NULL;
// --------------------------------------------------------------------------------
// BODYFILEINFO
// --------------------------------------------------------------------------------
typedef struct tagBODYFILEINFO {
HBODY hBody;
LPSTR pszCntId;
LPSTR pszCntLoc;
LPSTR pszFileName;
LPSTR pszFilePath;
BYTE fIsHtml;
IStream *pStmFile;
} BODYFILEINFO, *LPBODYFILEINFO;
// --------------------------------------------------------------------------------
// Prototypes
// --------------------------------------------------------------------------------
HRESULT CallRegInstall(LPCSTR szSection);
HRESULT ReplaceContentIds(LPSTREAM pStmHtml, LPBODYFILEINFO prgBody, DWORD cBodies);
int WinMainT(HINSTANCE hInst, HINSTANCE hInstPrev, LPTSTR pszCmdLine, int nCmdShow);
HRESULT MimeOleExplodeMhtmlFile(LPCSTR pszSrcFile, LPSTR pszDstDir, INT *pnError);
// --------------------------------------------------------------------------------
// IF_FAILEXIT_ERROR
// --------------------------------------------------------------------------------
#define IF_FAILEXIT_ERROR(_nError, hrExp) \
if (FAILED(hrExp)) { \
TraceResult(hr); \
*pnError = _nError; \
goto exit; \
} else
// --------------------------------------------------------------------------------
// ModuleEntry - Stolen from the CRT, used to shirink our code
// --------------------------------------------------------------------------------
int _stdcall ModuleEntry(void)
{
// Locals
int i;
STARTUPINFOA si;
LPTSTR pszCmdLine;
// Get Malloc
CoGetMalloc(1, &g_pMalloc);
// Get the command line
pszCmdLine = GetCommandLine();
// 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
SetErrorMode(SEM_FAILCRITICALERRORS);
// Parse the command line
if (*pszCmdLine == TEXT('\"'))
{
// Scan, and skip over, subsequent characters until another double-quote or a null is encountered.
while ( *++pszCmdLine && (*pszCmdLine != TEXT('\"')))
{};
// If we stopped on a double-quote (usual case), skip over it.
if (*pszCmdLine == TEXT('\"'))
pszCmdLine++;
}
else
{
while (*pszCmdLine > TEXT(' '))
pszCmdLine++;
}
// Skip past any white space preceeding the second token.
while (*pszCmdLine && (*pszCmdLine <= TEXT(' ')))
pszCmdLine++;
// Register
if (0 == lstrcmpi(c_szRegCmd, pszCmdLine))
{
CallRegInstall(c_szReg);
goto exit;
}
// Unregister
else if (0 == lstrcmpi(c_szUnRegCmd, pszCmdLine))
{
CallRegInstall(c_szUnReg);
goto exit;
}
// Get startup information...
si.dwFlags = 0;
GetStartupInfoA(&si);
// Call the real winmain
i = WinMainT(GetModuleHandle(NULL), NULL, pszCmdLine, si.dwFlags & STARTF_USESHOWWINDOW ? si.wShowWindow : SW_SHOWDEFAULT);
exit:
// Cleanup
SafeRelease(g_pMalloc);
// 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.
ExitProcess(i);
// Done
return i;
}
// --------------------------------------------------------------------------------
// WinMainT
// --------------------------------------------------------------------------------
int WinMainT(HINSTANCE hInst, HINSTANCE hInstPrev, LPTSTR pszCmdLine, int nCmdShow)
{
// Locals
HRESULT hr;
CHAR szRes[CCHMAX_RES];
CHAR szSource[CCHMAX_PATH_EXPLODER];
CHAR szDest[CCHMAX_PATH_EXPLODER];
LPSTR pszT;
DWORD i;
INT nError;
// Message
LoadString(hInst, IDS_TITLE, g_szTitle, ARRAYSIZE(g_szTitle));
// Message
LoadString(hInst, IDS_HELP, szRes, ARRAYSIZE(szRes));
// If Command Line is Empty...
if (NULL == pszCmdLine || StrStrA(pszCmdLine, szRes) || *pszCmdLine == '?' || lstrcmpi("\\?", pszCmdLine) == 0)
{
// Message
LoadString(hInst, IDS_CMDLINE_FORMAT, szRes, ARRAYSIZE(szRes));
// Message
MessageBox(NULL, szRes, g_szTitle, MB_OK | MB_ICONINFORMATION);
// Done
goto exit;
}
// Null Out Source and Dest
*szSource = '\0';
*szDest = '\0';
// If pszCmdLine specifies a specific, existing file...
if (PathFileExists(pszCmdLine))
{
// Copy To source
lstrcpyn(szSource, pszCmdLine, ARRAYSIZE(szSource));
// Pick a Temporary Location to store the thicket
GetTempPath(ARRAYSIZE(szDest), szDest);
}
// Otherwise, try to get a source
else
{
// Lets Upper Case the Command Line
CharUpper(pszCmdLine);
// Try to locate /SOURCE:
pszT = StrStrA(pszCmdLine, c_szSource);
// If we found /SOURCE, then read the contents...
if (pszT)
{
// Step over /SOURCE:
pszT += lstrlen(c_szSource);
// Initialize
i = 0;
// Read into szSource, until I hit a / or end of string...
while ('\0' != *pszT && '/' != *pszT && i < CCHMAX_PATH_EXPLODER)
szSource[i++] = *pszT++;
// Pound in a Null
szSource[i] = '\0';
// Strip Leading and Trailing Whitespace
UlStripWhitespace(szSource, TRUE, TRUE, NULL);
// See if file exists
if (FALSE == PathFileExists(szSource))
{
// Locals
CHAR szError[CCHMAX_RES + CCHMAX_PATH_EXPLODER];
// Message
LoadString(hInst, IDS_FILE_NOEXIST, szRes, ARRAYSIZE(szRes));
// Format the error message
wsprintf(szError, szRes, szSource);
// Message
INT nAnswer = MessageBox(NULL, szError, g_szTitle, MB_YESNO | MB_ICONEXCLAMATION );
// Done
if (IDNO == nAnswer)
goto exit;
// Otherwise, clear szSource
*szSource = '\0';
}
}
// No Source File, lets browser for one
if (FIsEmptyA(szSource))
{
// Locals
OPENFILENAME ofn;
CHAR rgszFilter[CCHMAX_PATH_EXPLODER];
CHAR szDir[MAX_PATH];
// Copy in the source of exploder.exe
GetModuleFileName(hInst, szDir, ARRAYSIZE(szDir));
// Initialize szDest
PathRemoveFileSpecA(szDir);
// Initialize ofn
ZeroMemory(&ofn, sizeof(OPENFILENAME));
// Initialize the STring
*szSource ='\0';
// Load the MHTML File Filter
LoadString(hInst, IDS_MHTML_FILTER, rgszFilter, ARRAYSIZE(rgszFilter));
// Fixup the String
ReplaceChars(rgszFilter, '|', '\0');
// Initialize the Open File Structure
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = NULL;
ofn.hInstance = hInst;
ofn.lpstrFilter = rgszFilter;
ofn.nFilterIndex = 1;
ofn.lpstrFile = szSource;
ofn.nMaxFile = CCHMAX_PATH_EXPLODER;
ofn.lpstrInitialDir = szDir;
ofn.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR;
// Get Open File Name
if (FALSE == GetOpenFileName(&ofn))
goto exit;
}
}
// Do we have a valid destination...
if (FALSE == PathIsDirectoryA(szDest))
{
// Try to locate /DEST:
pszT = StrStrA(pszCmdLine, c_szDest);
// If we found /DEST, then read the contents...
if (pszT)
{
// Step over /DEST:
pszT += lstrlen(c_szDest);
// Initialize
i = 0;
// Read into szSource, until I hit a / or end of string...
while ('\0' != *pszT && '/' != *pszT && i < CCHMAX_PATH_EXPLODER)
szDest[i++] = *pszT++;
// Pound in a Null
szDest[i] = '\0';
// Strip Leading and Trailing Whitespace
UlStripWhitespace(szDest, TRUE, TRUE, NULL);
// See if file exists
if (FALSE == PathIsDirectoryA(szDest))
{
// Locals
CHAR szError[CCHMAX_RES + CCHMAX_PATH_EXPLODER];
// Message
LoadString(hInst, IDS_DIRECTORY_NOEXIST, szRes, ARRAYSIZE(szRes));
// Format the error message
wsprintf(szError, szRes, szDest);
// Message
INT nAnswer = MessageBox(NULL, szError, g_szTitle, MB_YESNO | MB_ICONEXCLAMATION );
// Done
if (IDNO == nAnswer)
goto exit;
// Try to create the directory
if (FALSE == CreateDirectory(szDest, NULL))
{
// Message
LoadString(hInst, IDS_NOCREATE_DIRECTORY, szRes, ARRAYSIZE(szRes));
// Format the error message
wsprintf(szError, szRes, szDest);
// Message
INT nAnswer = MessageBox(NULL, szError, g_szTitle, MB_YESNO | MB_ICONEXCLAMATION );
// Done
if (IDNO == nAnswer)
goto exit;
// Clear *szDest
*szDest = '\0';
}
}
}
// No Source File, lets browser for one
if (FIsEmptyA(szDest))
{
// Copy in the source of exploder.exe
GetModuleFileName(hInst, szDest, ARRAYSIZE(szDest));
// Initialize szDest
PathRemoveFileSpecA(szDest);
// Failure
if (FALSE == BrowseForFolder(hInst, NULL, szDest, ARRAYSIZE(szDest), IDS_BROWSE_DEST, TRUE))
goto exit;
// Better be a directory
Assert(PathIsDirectoryA(szDest));
}
}
// Validate the dest and source
Assert(PathIsDirectoryA(szDest) && PathFileExists(szSource));
// Explode the file
nError = 0;
hr = MimeOleExplodeMhtmlFile(szSource, szDest, &nError);
// Failure ?
if (FAILED(hr) || 0 != nError)
{
// Locals
CHAR szError[CCHMAX_RES + CCHMAX_PATH_EXPLODER];
// Message
LoadString(hInst, nError, szRes, ARRAYSIZE(szRes));
// Need to format with file name ?
if (IDS_OPEN_FILE == nError || IDS_LOAD_FAILURE == nError || IDS_NO_HTML == nError)
{
// Format the error message
wsprintf(szError, szRes, szSource, hr);
}
// Otherwise,
else
{
// Format the error message
wsprintf(szError, szRes, hr);
}
// Message
MessageBox(NULL, szError, g_szTitle, MB_OK | MB_ICONEXCLAMATION);
}
exit:
// Done
return(1);
}
// --------------------------------------------------------------------------------
// MimeOleExplodeMhtmlFile
// --------------------------------------------------------------------------------
HRESULT MimeOleExplodeMhtmlFile(LPCSTR pszSrcFile, LPSTR pszDstDir, INT *pnError)
{
// Locals
HRESULT hr=S_OK;
IStream *pStmFile=NULL;
IMimeMessage *pMessage=NULL;
HBODY hRootHtml=NULL;
DWORD cMaxBodies;
DWORD cBodies=0;
FINDBODY FindBody={0};
DWORD cchDstDir;
DWORD iRootBody=0xffffffff;
HBODY hBody;
PROPVARIANT Variant;
SHELLEXECUTEINFO ExecuteInfo;
LPBODYFILEINFO prgBody=NULL;
LPBODYFILEINFO pInfo;
DWORD i;
IMimeBody *pBody=NULL;
// Trace
TraceCall("MimeOleExplodeMhtmlFile");
// Invalid Args
if (FALSE == PathIsDirectoryA(pszDstDir) || FALSE == PathFileExists(pszSrcFile) || NULL == pnError)
return TraceResult(E_INVALIDARG);
// Initialize
*pnError = 0;
// Get DstDir Length
cchDstDir = lstrlen(pszDstDir);
// Remove last \\ from pszDstDir
if (cchDstDir && pszDstDir[cchDstDir - 1] == '\\')
{
pszDstDir[cchDstDir - 1] = '\0';
cchDstDir--;
}
// Create a Mime Message
IF_FAILEXIT_ERROR(IDS_MEMORY, hr = MimeOleCreateMessage(NULL, &pMessage));
// Initialize the message
IF_FAILEXIT_ERROR(IDS_GENERAL_ERROR, hr = pMessage->InitNew());
// Create a stream on the file
IF_FAILEXIT_ERROR(IDS_OPEN_FILE, hr = OpenFileStream((LPSTR)pszSrcFile, OPEN_EXISTING, GENERIC_READ, &pStmFile));
// Load the Message
IF_FAILEXIT_ERROR(IDS_LOAD_FAILURE, hr = pMessage->Load(pStmFile));
// Invalid Message
if (MIME_S_INVALID_MESSAGE == hr)
{
*pnError = IDS_LOAD_FAILURE;
goto exit;
}
// Count the Bodies
IF_FAILEXIT(hr = pMessage->CountBodies(NULL, TRUE, &cMaxBodies));
// Allocate
IF_FAILEXIT_ERROR(IDS_MEMORY, hr = HrAlloc((LPVOID *)&prgBody, sizeof(BODYFILEINFO) * cMaxBodies));
// Zero
ZeroMemory(prgBody, sizeof(BODYFILEINFO) * cMaxBodies);
// Get the root body...
IF_FAILEXIT_ERROR(IDS_NO_HTML, hr = pMessage->GetTextBody(TXT_HTML, IET_DECODED, NULL, &hRootHtml));
// Loop through all the bodies
hr = pMessage->FindFirst(&FindBody, &hBody);
// Loop
while(SUCCEEDED(hr))
{
// Must have an hBody
Assert(hBody);
// Skip Multipart Bodies
if (S_FALSE == pMessage->IsContentType(hBody, STR_CNT_MULTIPART, NULL))
{
// Is this the root ?
if (hBody == hRootHtml)
iRootBody = cBodies;
// Readability
pInfo = &prgBody[cBodies];
// Better not over run prgBody
pInfo->hBody = hBody;
// Init the Variant
Variant.vt = VT_LPSTR;
// Get the Content Id
if (SUCCEEDED(pMessage->GetBodyProp(hBody, PIDTOSTR(PID_HDR_CNTID), 0, &Variant)))
pInfo->pszCntId = Variant.pszVal;
// Get the Content Location
if (SUCCEEDED(pMessage->GetBodyProp(hBody, PIDTOSTR(PID_HDR_CNTLOC), 0, &Variant)))
pInfo->pszCntLoc = Variant.pszVal;
// Generate a filename
if (SUCCEEDED(pMessage->GetBodyProp(hBody, PIDTOSTR(PID_ATT_GENFNAME), 0, &Variant)))
pInfo->pszFileName = Variant.pszVal;
// If its html, lets make sure that the filename has a .html file extension
pInfo->fIsHtml = (S_OK == pMessage->IsContentType(hBody, STR_CNT_TEXT, STR_SUB_HTML)) ? TRUE : FALSE;
// Take the filename and build the file path
Assert(pInfo->pszFileName);
// Don't Crash
if (NULL == pInfo->pszFileName)
{
hr = TraceResult(E_UNEXPECTED);
goto exit;
}
// Validate Extension
if (pInfo->fIsHtml)
{
// Get Extension
LPSTR pszExt = PathFindExtensionA(pInfo->pszFileName);
// If Null or not .html..
if (NULL == pszExt || lstrcmpi(pszExt, ".html") != 0)
{
// Re-allocate pInfo->pszFileName...
IF_FAILEXIT_ERROR(IDS_MEMORY, hr = HrRealloc((LPVOID *)&pInfo->pszFileName, lstrlen(pInfo->pszFileName) + 10));
// Rename the Extension
PathRenameExtensionA(pInfo->pszFileName, ".html");
}
}
// Build that full file path
IF_FAILEXIT_ERROR(IDS_MEMORY, hr = HrAlloc((LPVOID *)&pInfo->pszFilePath, lstrlen(pszDstDir) + lstrlen(pInfo->pszFileName) + 10));
// Formath the filepath
wsprintf(pInfo->pszFilePath, "%s\\%s", pszDstDir, pInfo->pszFileName);
// Save the body to the file
IF_FAILEXIT(hr = pMessage->BindToObject(hBody, IID_IMimeBody, (LPVOID *)&pBody));
// Save to the file
IF_FAILEXIT(hr = pBody->SaveToFile(IET_DECODED, pInfo->pszFilePath));
// Open a file stream
if (pInfo->fIsHtml)
{
// Open it if its html
IF_FAILEXIT(hr = OpenFileStream(pInfo->pszFilePath, OPEN_ALWAYS, GENERIC_READ | GENERIC_WRITE, &pInfo->pStmFile));
}
// Increment cBodies
cBodies++;
}
// Loop through all the bodies
hr = pMessage->FindNext(&FindBody, &hBody);
}
// Reset hr
hr = S_OK;
// Root Body was not found
Assert(iRootBody != 0xffffffff);
// Bad News
if (0xffffffff == iRootBody)
{
hr = TraceResult(E_UNEXPECTED);
goto exit;
}
// Walk through and fixup all HTML files and close all streams
for (i=0; i<cBodies; i++)
{
// Readability
pInfo = &prgBody[i];
// If HTML...
if (pInfo->fIsHtml)
{
// Better have an open stream
Assert(pInfo->pStmFile);
// Failure
if (NULL == pInfo->pStmFile)
{
hr = TraceResult(E_UNEXPECTED);
goto exit;
}
// Replace all the CID references with file references...
ReplaceContentIds(pInfo->pStmFile, prgBody, cBodies);
}
// Release this stream
SafeRelease(pInfo->pStmFile);
}
// Launch the Currently Registered HTML Editor ontop of iRootBody pszFilePath
ZeroMemory(&ExecuteInfo, sizeof(SHELLEXECUTEINFO));
ExecuteInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
ExecuteInfo.cbSize = sizeof(SHELLEXECUTEINFO);
ExecuteInfo.lpVerb = "Edit";
ExecuteInfo.lpFile = prgBody[iRootBody].pszFilePath;
ExecuteInfo.lpParameters = NULL;
ExecuteInfo.lpDirectory = pszDstDir;
ExecuteInfo.nShow = SW_SHOWNORMAL;
// Compress szBlobFile
ShellExecuteEx(&ExecuteInfo);
exit:
// General Error
if (FAILED(hr) && 0 == *pnError)
*pnError = IDS_GENERAL_ERROR;
// Free prgBody
if (prgBody)
{
// Loop
for (i=0; i<cBodies; i++)
{
SafeMemFree(prgBody[i].pszCntId);
SafeMemFree(prgBody[i].pszCntLoc);
SafeMemFree(prgBody[i].pszFileName);
SafeMemFree(prgBody[i].pszFilePath);
SafeRelease(prgBody[i].pStmFile);
}
// Free the Array
CoTaskMemFree(prgBody);
}
// Cleanup
SafeRelease(pStmFile);
SafeRelease(pBody);
SafeRelease(pMessage);
// Done
return hr;
}
// --------------------------------------------------------------------------------
// ReplaceContentIds
// --------------------------------------------------------------------------------
HRESULT ReplaceContentIds(LPSTREAM pStmHtml, LPBODYFILEINFO prgBody, DWORD cBodies)
{
// Locals
HRESULT hr=S_OK;
DWORD cb;
LPSTR pszFound;
LPSTR pszT;
LPSTR pszHtml=NULL;
LPSTR pszCntId=NULL;
DWORD i;
DWORD cchCntId;
ULARGE_INTEGER uliSize;
// Trac
TraceCall("ReplaceContentIds");
// Invalid Args
Assert(pStmHtml && prgBody && cBodies);
// Loop through the bodies
for (i=0; i<cBodies; i++)
{
// No Content-ID here...
if (NULL == prgBody[i].pszCntId)
continue;
// Better have a filename
Assert(prgBody[i].pszFileName);
// Load the stream into memory...
IF_FAILEXIT(hr = HrGetStreamSize(pStmHtml, &cb));
// Allocate Memory
IF_FAILEXIT(hr = HrAlloc((LPVOID *)&pszHtml, cb + 1));
// Rewind
IF_FAILEXIT(hr = HrRewindStream(pStmHtml));
// Read the Stream
IF_FAILEXIT(hr = pStmHtml->Read(pszHtml, cb, NULL));
// Stuff Null terminator
pszHtml[cb] = '\0';
// Kill pStmHtml
uliSize.QuadPart = 0;
IF_FAILEXIT(hr = pStmHtml->SetSize(uliSize));
// Allocate Memory
IF_FAILEXIT(hr = HrAlloc((LPVOID *)&pszCntId, lstrlen(prgBody[i].pszCntId) + lstrlen("cid:") + 5));
// Format
pszT = prgBody[i].pszCntId;
if (*pszT == '<')
pszT++;
wsprintf(pszCntId, "cid:%s", pszT);
// Remove trailing >
cchCntId = lstrlen(pszCntId);
if (pszCntId[cchCntId - 1] == '>')
pszCntId[cchCntId - 1] = '\0';
// Set pszT
pszT = pszHtml;
// Begin replace loop
while(1)
{
// Find pszCntId
pszFound = StrStrA(pszT, pszCntId);
// Done
if (NULL == pszFound)
{
// Write from pszT to pszFound
IF_FAILEXIT(hr = pStmHtml->Write(pszT, (pszHtml + cb) - pszT, NULL));
// Done
break;
}
// Write from pszT to pszFound
IF_FAILEXIT(hr = pStmHtml->Write(pszT, pszFound - pszT, NULL));
// Write
IF_FAILEXIT(hr = pStmHtml->Write(prgBody[i].pszFileName, lstrlen(prgBody[i].pszFileName), NULL));
// Set pszT
pszT = pszFound + lstrlen(pszCntId);
}
// Commit
IF_FAILEXIT(hr = pStmHtml->Commit(STGC_DEFAULT));
// Cleanup
SafeMemFree(pszHtml);
SafeMemFree(pszCntId);
}
exit:
// Cleanup
SafeMemFree(pszHtml);
SafeMemFree(pszCntId);
// Done
return hr;
}
// --------------------------------------------------------------------------------
// CallRegInstall
// --------------------------------------------------------------------------------
HRESULT CallRegInstall(LPCSTR szSection)
{
int cch;
HRESULT hr;
HINSTANCE hAdvPack, hinst;
REGINSTALL pfnri;
char szExploderDll[CCHMAX_PATH_EXPLODER], szDir[CCHMAX_PATH_EXPLODER];
STRENTRY seReg[2];
STRTABLE stReg;
char c_szExploder[] = "EXPLODER";
char c_szExploderDir[] = "EXPLODER_DIR";
hr = E_FAIL;
hinst = GetModuleHandle(NULL);
hAdvPack = LoadLibraryA(c_szAdvPackDll);
if (hAdvPack != NULL)
{
// Get Proc Address for registration util
pfnri = (REGINSTALL)GetProcAddress(hAdvPack, achREGINSTALL);
if (pfnri != NULL)
{
stReg.cEntries = 0;
stReg.pse = seReg;
GetModuleFileName(hinst, szExploderDll, ARRAYSIZE(szExploderDll));
seReg[stReg.cEntries].pszName = c_szExploder;
seReg[stReg.cEntries].pszValue = szExploderDll;
stReg.cEntries++;
lstrcpy(szDir, szExploderDll);
cch = lstrlen(szDir);
for ( ; cch > 0; cch--)
{
if (szDir[cch] == '\\')
{
szDir[cch] = 0;
break;
}
}
seReg[stReg.cEntries].pszName = c_szExploderDir;
seReg[stReg.cEntries].pszValue = szDir;
stReg.cEntries++;
// Call the self-reg routine
hr = pfnri(hinst, szSection, &stReg);
}
FreeLibrary(hAdvPack);
}
return(hr);
}