On Tue, Jan 3, 2012 at 4:57 PM, Kevin Hebert <ke...@legendary-immersion.com>
wrote:
> The question is though, how do I extract it? I'd thought I was going
> about it the right way, but apparently I'm not.
>
>

I did it by using these two C++ helper functions at the end of the email.
For each file I needed to be extracted I called ExtractFileToCaData(). This
function is invoked N times from an execute action and streams the binary
table data for each file into the custom action data for use by my deferred
action.

Something like this:

 hr = ExtractFileToCa(k_wszBinaryKeyDUConfig, L"file1.dll",
&pwszCustomActionData);
 ExitOnFailure1(hr, "Failed to extract %ls from MSI", k_wszBinaryKeyFile1);
 hr = ExtractFileToCa(k_wszBinaryKeyEPWCrypto, L"file2.dll",
&pwszCustomActionData);
 ExitOnFailure1(hr, "Failed to extract %ls from MSI", k_wszBinaryKeyFile2);
 hr = ExtractFileToCa(k_wszBinaryKeyLibEay32, L"file3.dll",
&pwszCustomActionData);
 ExitOnFailure1(hr, "Failed to extract %ls from MSI", k_wszBinaryKeyFile3);

 // Schedule Deferred Action
 hr = WcaDoDeferredAction(L"AxedaGenConfigExec", pwszCustomActionData,
COST_AXEDA);
 ExitOnFailure(hr, "Failed to schedule Deferred Action.");


The deferred action then calls ExtractFileToDir() for each file it needs to
put in a temporary location on disk.

Something like this:

 // Extract files to temp directory.
 hr = PathCreateTempDirectory(NULL, L"HRCAAxeda%03x", 999, &pwszTempDir);
 ExitOnFailure(hr, "Failed to load create temp directory for DLL
extraction.");
 extractedFiles = true;
 hr = ExtractFileToDir(&pwszCustomActionData, pwszTempDir);
 ExitOnFailure(hr, "Failed to extract file from CA");
 hr = ExtractFileToDir(&pwszCustomActionData, pwszTempDir);
 ExitOnFailure(hr, "Failed to extract file from CA");
 hr = ExtractFileToDir(&pwszCustomActionData, pwszTempDir);
 ExitOnFailure(hr, "Failed to extract file from CA");
 <call into DLL, whatever...>

LExit:
 if (extractedFiles)
 {

  DirEnsureDeleteEx(pwszTempDir, DIR_DELETE_FILES | DIR_DELETE_RECURSE |
DIR_DELETE_SCHEDULE);
  WcaLog(LOGMSG_VERBOSE, "Removed extracted files from '%ls': ",
pwszTempDir);
 }
 <other cleanup actions>



I ensure that the extracted files are deleted at the end of my deferred
action. (either due to success or failure)

NOTE: For the C++ challenged, the Wca* functions are thin WiX C++ custom
action helper wrappers for the underlying MSI functionality.

Bill


const LPCWSTR k_wszBinaryTableQuery =
 L"SELECT `Binary`.`Name`, `Binary`.`Data` "
 L"FROM   `Binary` "
 L"WHERE  `Binary`.`Name` = '%s'";

HRESULT ExtractFileToCaData(LPCWSTR pwszBinaryKey, LPWSTR pwszFileName,
LPWSTR *ppwszCustomActionData)
{
 HRESULT hr = S_OK;
 PMSIHANDLE hView = NULL;
 PMSIHANDLE hRec = NULL;
 LPBYTE pbData = NULL;
 DWORD  cbData = 0;
 LPWSTR pwszQuery = NULL;
 LPWSTR pwszPath = NULL;
 LPWSTR pwszIdentifier = NULL;
 // Save filename to CA
 hr = WcaWriteStringToCaData(pwszFileName, ppwszCustomActionData);
 ExitOnFailure(hr, "Failed to set file name into CustomActionData from
ExtractFileToCa");
 // Find the binary data
 hr = StrAllocFormatted(&pwszQuery, k_wszBinaryTableQuery, pwszBinaryKey);
 ExitOnFailure(hr, "Failed to format MSI SQL query in ExtractFileToDir");
 hr = WcaOpenExecuteView(pwszQuery, &hView);
 ExitOnFailure(hr, "Failed to execute ExtratFileToDir query");
 hr = WcaFetchRecord(hView, &hRec);
 ExitOnFailure1(hr, "Failed to fetch row for Binary PK: '%ls'",
pwszBinaryKey);
 hr = WcaGetRecordString(hRec, 1, &pwszIdentifier);
 ExitOnFailure1(hr, "Failed to get Identifier column for BinaryPK: '%ls'",
pwszBinaryKey);
 WcaLog(LOGMSG_TRACEONLY, "Identifier column: '%ls'", pwszIdentifier);
 hr = WcaGetRecordStream(hRec, 2, &pbData, &cbData);
 ExitOnFailure1(hr, "Failed to get Data column for BinaryPK: '%ls'",
pwszBinaryKey);
 hr = WcaWriteStreamToCaData(pbData, cbData, ppwszCustomActionData);
 MessageExitOnFailure1(hr, ERROR_INSTALL_FAILURE, "Failure to extract '%ls'
from MSI Binary table.", pwszFileName);
LExit:
 ReleaseStr(pwszQuery);
 ReleaseStr(pwszPath);
 ReleaseStr(pwszIdentifier);
 WcaFreeStream(pbData);
 return hr;
}

HRESULT ExtractFileToDir(LPWSTR *ppwszCustomActionData, LPWSTR pwszTempDir)
{
 HRESULT hr = S_OK;
 LPBYTE pbData = NULL;
 DWORD cbData = 0;
 LPWSTR pwszFileName = NULL;
 LPWSTR pwszPath = NULL;
 hr = WcaReadStringFromCaData(ppwszCustomActionData, &pwszFileName);
 ExitOnFailure(hr, "Failed to get filename from CustomActionData");
 hr = StrAllocFormatted(&pwszPath, L"%s%s", pwszTempDir, pwszFileName);
 ExitOnFailure1(hr, "Failed to construct full path to extracted filename:
'%ls'", pwszFileName);
 hr = WcaReadStreamFromCaData(ppwszCustomActionData, &pbData, &cbData);
 MessageExitOnFailure1(hr, ERROR_INSTALL_FAILURE, "Failure to extract '%ls'
from CustomActionData", pwszFileName);
 hr = FileWrite(pwszPath, 0, pbData, cbData, NULL);
 WcaLog(LOGMSG_VERBOSE, "Extracted '%ls'", pwszPath);
LExit:
 ReleaseStr(pwszFileName);
 ReleaseStr(pwszPath);
 WcaFreeStream(pbData);
 return hr;
}
------------------------------------------------------------------------------
Write once. Port to many.
Get the SDK and tools to simplify cross-platform app development. Create 
new or port existing apps to sell to consumers worldwide. Explore the 
Intel AppUpSM program developer opportunity. appdeveloper.intel.com/join
http://p.sf.net/sfu/intel-appdev
_______________________________________________
WiX-users mailing list
WiX-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/wix-users

Reply via email to