I have a custom action dll, written in C++, which is invoked using a button during install. The purpose of the custom action is to capture the clipboard contents and evaluate whether or not the contents is in the format of a valid product key. If it is, then the 'PRODUCTKEY' property is updated, as is another property which lets me know that we have been successful.
<Control Id="PasteButton" Type="PushButton" X="25" Y="176" Width="25" Height="16" Default="yes" Text="Paste" >
<Publish Event="DoAction" Value="MsiCheckClipboardForKey" Order="1">1</Publish>
<Publish Property="PRODUCTKEY" Value="[PRODUCTKEY]" Order="2">ClipboardSuccess = 1</Publish>
</Control>
Unfortunately, the install is failing after this custom action has been called. However, from looking at the install log my properties have been changed which tends to suggest that my custom action code is running successfully.
MSI (c) (20:4C) [12:04:55:281]: Invoking remote custom action. DLL: C:\Users\xxxxx\AppData\Local\Temp\MSI5652.tmp, Entrypoint: msiCheckClipboardForKey
MSI (c) (20!C4) [12:04:57:746]: PROPERTY CHANGE: Modifying ClipboardSuccess property. Its current value is '0'. Its new value: '1'.
MSI (c) (20!C4) [12:04:57:746]: PROPERTY CHANGE: Adding PRODUCTKEY property. Its value is 'xxxxx-xxxxx-xxxxx-xxxxx-xxxxx'.
Action ended 12:04:57: MsiCheckClipboardForKey. Return value 3.
DEBUG: Error 2896: Executing action MsiCheckClipboardForKey failed.
This is the custom action code:
#include "StdAfx.h"
#include "Debug.h"
#pragma comment(linker, "/EXPORT:msiCheckClipboardForKey=_msiCheckClipboardForKey@4")
BOOL GetClipboardText ( IN OUT CString& strClipBoardText)
{
strClipBoardText = _T("");
BOOL bOK = FALSE;
UINT uFormat = 0;
// We need to explicitly query the clipboard for UNICODE text
// if we have a UNICODE application
#ifdef _UNICODE
uFormat = CF_UNICODETEXT;
#else
uFormat = CF_TEXT;
#endif
if ( ::IsClipboardFormatAvailable ( uFormat ) )
{
if ( ::OpenClipboard ( NULL ) )
{
HANDLE hClipBrdData = NULL;
if ( HANDLE hClipBrdData = ::GetClipboardData ( uFormat ) )
{
if ( LPTSTR lpClipBrdText = ( LPTSTR ) ::GlobalLock ( hClipBrdData ) )
{
MessageBox("Clipboard Text",lpClipBrdText,NULL,NULL);
strClipBoardText = lpClipBrdText;
::GlobalUnlock ( hClipBrdData );
bOK = TRUE;
}
}
::CloseClipboard();
}
}
return bOK;
}
extern "C" UINT __stdcall msiCheckClipboardForKey(MSIHANDLE hMSI)
{
CString strClipboardText ( _T("") );
if ( GetClipboardText ( strClipboardText ) )
{
DebugMsg ( hMSI, _T("Found clipboard text") );
strClipboardText.Trim();
// Look at the length. Is it 25 (wih no dashes/slashes) or 29 (with dashes/slashes)?
BOOL bValidLength = strClipboardText.Find ( '-' ) != -1 || strClipboardText.Find ( '/' ) != -1 ? strClipboardText.GetLength() == 29 : strClipboardText.GetLength() == 25;
DebugMsg ( hMSI, _T("Is it a product key? %b",bValidLength) );
if ( bValidLength )
{
//strClipboardText.Remove ( '-' );
//strClipboardText.Remove ( '/' );
MessageBox("Formatted Clipboard Text",strClipboardText,NULL,NULL);
MsiSetProperty(hMSI, "ClipboardSuccess", "1");
MsiSetProperty(hMSI, "PRODUCTKEY", strClipboardText);
return 0;
}
}
return 1; // None-zero is error state
}
Not sure what the problem could be, even more so as the custom action does seem to be executed as the properties are set correctly.