cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Cary_R
Level 11

C# Custom Action Crashing in ControlEvent

Hey guys,

Has anyone tried the combination of a C# custom action launched from a ControlEvent?

I have been finding that attempting to use MsiGetProperty() will crash Msiexec when my function exits for some reason. It is completely fine when the action inserted directly in the sequence, or if I pass parameters explicitly instead of using MsiGetProperty().

Here's how I have MsiGetProperty PInvoke'd:

public static extern UInt32 MsiGetProperty(IntPtr install, string name, [Out] StringBuilder value, ref uint valueSize);

(And, yes yes, I am sure it works in DTF...)
Labels (1)
0 Kudos
(5) Replies
MichaelU
Level 12 Flexeran
Level 12 Flexeran

Your P/Invoke is incorrect (see http://pinvoke.net/default.aspx/msi.MsiGetProperty), but I would only expect that to manifest in 64-bit code. But what's probably more important is how you're calling it. Note that MSI is particularly picky about its buffer handling. Have you cross-referenced the implementation in InstallShield.Interop.Msi.dll?
0 Kudos
Cary_R
Level 11

MichaelU wrote:
Your P/Invoke is incorrect (see http://pinvoke.net/default.aspx/msi.MsiGetProperty), but I would only expect that to manifest in 64-bit code. But what's probably more important is how you're calling it. Note that MSI is particularly picky about its buffer handling. Have you cross-referenced the implementation in InstallShield.Interop.Msi.dll?


Thanks Mike,

I actually had made the change you recommended prior to posting (cross referencing the Wix implementation, actually). The issue still persists.

[DllImport("msi", CharSet = CharSet.Auto)]
public static extern int MsiGetProperty(int install, string name, [Out] StringBuilder value, ref int valueSize);

As far as how I'm calling it, it's as simple as you'd expect:

int buffer = 1000;
int retCode;

retCode = MsiGetProperty(hMSI, "IS_SQLSERVER_CONNSTRING", SqlServerConnString, ref buffer);

//some stuff

return ERROR_SUCCESS;

Now, the strange thing is that it works fine like this--it gets the property value and returns ERROR_SUCCESS. It is when the function exits, and control is passed back to the install is when Msiexec.exe crashes. I can use MsiSetProperty to write debug messages to the logfile without incident--it seems to only relate to the use of MsiGetProperty().
0 Kudos
MichaelU
Level 12 Flexeran
Level 12 Flexeran

How do you initialize SqlServerConnString? Are you calling something like EnsureCapacity on it? Without that or possibly some further annotations in your P/Invoke, you're telling MSI it's okay to write to memory that you don't actually own.
0 Kudos
Cary_R
Level 11

Here's the whole thing I have set up to test this issue, as of this writing:

        public int CA(int hMSI)
{
Debugger.Launch();
StringBuilder SqlServerConnString = new StringBuilder();
int buffer = 10000;
int retCode;
try
{
retCode = MsiInterop.MsiGetProperty(hMSI, "IS_SQLSERVER_CONNSTRING", SqlServerConnString, ref buffer);
}
catch (Exception e)
{
MsiInterop.CELog(hMSI, "Exception: " + e.Message);
}

return 0;
}


So, nothing particularly fancy--just the default StringBuilder Constructor.
0 Kudos
Cary_R
Level 11

But, this does indeed seem to help resolve the issue.

        public int CA(int hMSI)
{
StringBuilder SqlServerConnString = new StringBuilder();
SqlServerConnString.EnsureCapacity(1000);
int buffer = 1000;
int retCode;
try
{
retCode = MsiInterop.MsiGetProperty(hMSI, "IS_SQLSERVER_CONNSTRING", SqlServerConnString, ref buffer);
}
catch (Exception e)
{
MsiInterop.CELog(hMSI, "Exception: " + e.Message);
}
return 0;
}


Thanks much, Mike! Your explanation makes sense as to why to do it this way, but it seems strange that it only causes a problem from a ControlEvent.
0 Kudos