我有一个WiX的安装程序和一个自定义操作(加上撤消和回滚)吧,它使用从安装程序的属性。 自定义动作有发生后,所有的文件都在硬盘上。 看来,你需要在这个WXS文件16项; 八根内,如下所示:
<CustomAction Id="SetForRollbackDo" Execute="immediate" Property="RollbackDo" Value="[MYPROP]"/>
<CustomAction Id="RollbackDo" Execute="rollback" BinaryKey="MyDLL" DllEntry="UndoThing" Return="ignore"/>
<CustomAction Id="SetForDo" Execute="immediate" Property="Do" Value="[MYPROP]"/>
<CustomAction Id="Do" Execute="deferred" BinaryKey="MyDLL" DllEntry="DoThing" Return="check"/>
<CustomAction Id="SetForRollbackUndo" Execute="immediate" Property="RollbackUndo" Value="[MYPROP]"/>
<CustomAction Id="RollbackUndo" Execute="rollback" BinaryKey="MyDLL" DllEntry="DoThing" Return="ignore"/>
<CustomAction Id="SetForUndo" Execute="immediate" Property="Undo" Value="[MYPROP]"/>
<CustomAction Id="Undo" Execute="deferred" BinaryKey="MyDLL" DllEntry="UndoThing" Return="check"/>
和八中InstallExecuteSequence
,就像这样:
<Custom Action="SetForRollbackDo" After="InstallFiles">REMOVE<>"ALL"</Custom>
<Custom Action="RollbackDo" After="SetForRollbackDo">REMOVE<>"ALL"</Custom>
<Custom Action="SetForDo" After="RollbackDo">REMOVE<>"ALL"</Custom>
<Custom Action="Do" After="SetForDo">REMOVE<>"ALL"</Custom>
<Custom Action="SetForRollbackUndo" After="InstallInitialize">REMOVE="ALL"</Custom>
<Custom Action="RollbackUndo" After="SetForRollbackUndo">REMOVE="ALL"</Custom>
<Custom Action="SetForUndo" After="RollbackUndo">REMOVE="ALL"</Custom>
<Custom Action="Undo" After="SetForUndo">REMOVE="ALL"</Custom>
有没有更好的办法?
写WiX的安装程序,当我遇到同样的问题来了。 我对这个问题的方法是大多喜欢迈克建议,我有一个博客帖子实现WiX的自定义操作第2部分:使用自定义表 。
总之,你可以定义自定义表为您的数据:
<CustomTable Id="LocalGroupPermissionTable">
<Column Id="GroupName" Category="Text" PrimaryKey="yes" Type="string"/>
<Column Id="ACL" Category="Text" PrimaryKey="no" Type="string"/>
<Row>
<Data Column="GroupName">GroupToCreate</Data>
<Data Column="ACL">SeIncreaseQuotaPrivilege</Data>
</Row>
</CustomTable>
然后写一个直接自定义操作来安排推迟,回滚和提交自定义操作:
extern "C" UINT __stdcall ScheduleLocalGroupCreation(MSIHANDLE hInstall)
{
try {
ScheduleAction(hInstall,L"SELECT * FROM CreateLocalGroupTable", L"CA.LocalGroupCustomAction.deferred", L"create");
ScheduleAction(hInstall,L"SELECT * FROM CreateLocalGroupTable", L"CA.LocalGroupCustomAction.rollback", L"create");
}
catch( CMsiException & ) {
return ERROR_INSTALL_FAILURE;
}
return ERROR_SUCCESS;
}
下面的代码演示了如何安排一个自定义操作。 基本上你只打开自定义表,读取所需的属性,然后格式化需要到CustomActionData属性(我用的是表格的属性(可以通过调用MsiViewGetColumnInfo()获取任何自定义表的架构) /propname:value
,虽然你可以使用任何你想要的)。
void ScheduleAction(MSIHANDLE hInstall,
const wchar_t *szQueryString,
const wchar_t *szCustomActionName,
const wchar_t *szAction)
{
CTableView view(hInstall,szQueryString);
PMSIHANDLE record;
//For each record in the custom action table
while( view.Fetch(record) ) {
//get the "GroupName" property
wchar_t recordBuf[2048] = {0};
DWORD dwBufSize(_countof(recordBuf));
MsiRecordGetString(record, view.GetPropIdx(L"GroupName"), recordBuf, &dwBufSize);
//Format two properties "GroupName" and "Operation" into
//the custom action data string.
CCustomActionDataUtil formatter;
formatter.addProp(L"GroupName", recordBuf);
formatter.addProp(L"Operation", szAction );
//Set the "CustomActionData" property".
MsiSetProperty(hInstall,szCustomActionName,formatter.GetCustomActionData());
//Add the custom action into installation script. Each
//MsiDoAction adds a distinct custom action into the
//script, so if we have multiple entries in the custom
//action table, the deferred custom action will be called
//multiple times.
nRet = MsiDoAction(hInstall,szCustomActionName);
}
}
至于实施推迟,回滚和提交自定义操作,我更喜欢使用只有一个功能,并使用MsiGetMode()来区分应该做什么:
extern "C" UINT __stdcall LocalGroupCustomAction(MSIHANDLE hInstall)
{
try {
//Parse the properties from the "CustomActionData" property
std::map<std::wstring,std::wstring> mapProps;
{
wchar_t szBuf[2048]={0};
DWORD dwBufSize = _countof(szBuf); MsiGetProperty(hInstall,L"CustomActionData",szBuf,&dwBufSize);
CCustomActionDataUtil::ParseCustomActionData(szBuf,mapProps);
}
//Find the "GroupName" and "Operation" property
std::wstring sGroupName;
bool bCreate = false;
std::map<std::wstring,std::wstring>::const_iterator it;
it = mapProps.find(L"GroupName");
if( mapProps.end() != it ) sGroupName = it->second;
it = mapProps.find(L"Operation");
if( mapProps.end() != it )
bCreate = wcscmp(it->second.c_str(),L"create") == 0 ? true : false ;
//Since we know what opeartion to perform, and we know whether it is
//running rollback, commit or deferred script by MsiGetMode, the
//implementation is straight forward
if( MsiGetMode(hInstall,MSIRUNMODE_SCHEDULED) ) {
if( bCreate )
CreateLocalGroup(sGroupName.c_str());
else
DeleteLocalGroup(sGroupName.c_str());
}
else if( MsiGetMode(hInstall,MSIRUNMODE_ROLLBACK) ) {
if( bCreate )
DeleteLocalGroup(sGroupName.c_str());
else
CreateLocalGroup(sGroupName.c_str());
}
}
catch( CMsiException & ) {
return ERROR_INSTALL_FAILURE;
}
return ERROR_SUCCESS;
}
利用上述技术,设定您可以自定义操作表减为5项典型的自定义操作:
<CustomAction Id="CA.ScheduleLocalGroupCreation"
Return="check"
Execute="immediate"
BinaryKey="CustomActionDLL"
DllEntry="ScheduleLocalGroupCreation"
HideTarget="yes"/>
<CustomAction Id="CA.ScheduleLocalGroupDeletion"
Return="check"
Execute="immediate"
BinaryKey="CustomActionDLL"
DllEntry="ScheduleLocalGroupDeletion"
HideTarget="yes"/>
<CustomAction Id="CA.LocalGroupCustomAction.deferred"
Return="check"
Execute="deferred"
BinaryKey="CustomActionDLL"
DllEntry="LocalGroupCustomAction"
HideTarget="yes"/>
<CustomAction Id="CA.LocalGroupCustomAction.commit"
Return="check"
Execute="commit"
BinaryKey="CustomActionDLL"
DllEntry="LocalGroupCustomAction"
HideTarget="yes"/>
<CustomAction Id="CA.LocalGroupCustomAction.rollback"
Return="check"
Execute="rollback"
BinaryKey="CustomActionDLL"
DllEntry="LocalGroupCustomAction"
HideTarget="yes"/>
而InstallSquence表只有两个条目:
<InstallExecuteSequence>
<Custom Action="CA.ScheduleLocalGroupCreation"
After="InstallFiles">
Not Installed
</Custom>
<Custom Action="CA.ScheduleLocalGroupDeletion"
After="InstallFiles">
Installed
</Custom>
</InstallExecuteSequence>
此外,随着一点点的努力大部分代码可以被写入到被重用(如自定义表中读取,得到的属性,格式化所需的性能和设置CustomActionData属性),并在自定义操作表中的条目现在没有专用(应用程序特定数据被写入定制表),我们可以把自定义操作表中它自己的文件,只是包含在每个WiX工程。
对于自定义操作DLL文件,因为应用程序数据从定制表中读取,我们可以保持应用程序的具体细节出来的DLL实现的,因此自定义操作表可以成为一个库,从而更容易重用。
这是我目前写我的WiX的自定义操作,如果有人知道如何进一步提高我将非常感激。 :)
(您也可以在我的博客文章的完整源代码, 实现维克斯自定义操作第2部分:使用自定义表 )。
该WiX的自定义操作是一个伟大的模式可以遵循。 在这种情况下,你只有声明,与CustomAction
,立即行动起来,在推迟行动,并回滚操作。 你只时间表, Custom
,立即行动起来,在眼前的动作是在本机DLL实现代码。
然后,在立即采取行动的代码 ,你叫MsiDoAction
安排回滚和递延行动:他们被推迟,他们在调用点写进剧本MsiDoAction
,而不是立即执行。 你需要调用MsiSetProperty
以及设置自定义操作数据。
下载维克斯源代码,并学习如何IISExtension
工作,例如。 维克斯行动一般解析定制表,并生成基于该表为递延行动的财产数据。
如果您有需要支持回滚复杂的自定义操作,你可能会考虑写一个维克斯扩展。 扩展通常提供创作支持(也被映射到MSI表条目,即新的XML标记),加上自定义操作自动调度。
这不仅仅是编写自定义操作更多的工作,但一旦你的CAS达到的复杂性一定程度,易用性的创作是扩展提供了可能是值得的。