I have a C++ application in Visual Studio 2010 and I have a Windows Installer (i.e. setup project) to install it. I want to be able to invoke the installer like this:
Setup1.msi MYPROPERTY=MyValue
And then be able to extract the value "MyValue" from the property from within my custom action. I tried to get it working by following this tutorial(C++ custom actions) and this tutorial (passing arguments to custom actions, but in C#) combined with some MSDN searches to get this code:
#define WINDOWS_LEAN_AND_MEAN
#include <Windows.h>
#include <msi.h>
#include <msiquery.h>
#include <stdio.h>
BOOL APIENTRY DllMain(HANDLE, DWORD, LPVOID) {
return TRUE;
}
UINT APIENTRY InstallCustomAction(MSIHANDLE install_handle) {
static const wchar_t* kPropertyName = L"MYPROPERTY";
//auto msi_handle = MsiGetActiveDatabase(install_handle);
DWORD n = 0;
//auto result = MsiGetProperty(msi_handle, kPropertyName, L"", &n);
auto result = MsiGetProperty(install_handle, kPropertyName, L"", &n);
wchar_t* value = nullptr;
if (result == ERROR_MORE_DATA) {
++n;
value = new wchar_t[n];
//result = MsiGetProperty(msi_handle, kPropertyName, value, &n);
result = MsiGetProperty(install_handle, kPropertyName, value, &n);
}
if (result == ERROR_SUCCESS) {
wchar_t buffer[128];
swprintf_s(buffer, L"n = %d, value = %s", n, value);
MessageBox(nullptr, buffer, L"CustomAction", MB_OK);
} else {
MessageBox(nullptr, L"Error reading property", L"Error", MB_OK);
}
delete value;
//MsiCloseHandle(msi_handle);
return ERROR_SUCCESS;
}
I'm following the C# tutorial exactly in terms of the IDE (I have Entry Point
set to InstallCustomAction
and Custom Action
Data set to /MYPROPERTY=[MYPROPERTY]
) The custom action fires correctly but I don't get the parameter.
With the code as-is, I get n=0. If I use the msi_handle
from MsiGetActiveDatabase
I get an error (i.e. MsiGetProperty returns something other than ErrorSuccess).
How can I get the property that the user passes in on the command line from within my custom action?
There's no need to call MsiGetActiveDatabase. From what you've written it sounds like your custom action is scheduled for deferred execution. In that scenario you should be trying to get the property named "CustomActionData".