CustomAction 在开发计算机上成功,在部署计算机上失败
我正在创建一个 WiX 安装程序来安装连接到数据库的程序。为了解决这个问题,我创建了一个 C dll,它检查服务器上是否存在某个 SQL 实例:
extern "C" UINT __stdcall DBConTest(MSIHANDLE hInstaller)
{
FILE *fp;
fp = fopen("dbcontestdll.txt", "w");
_ConnectionPtr pCon;
int iErrCode;
HRESULT hr;
UINT rc;
//init COM
fwprintf(fp, L"entering dbcontest\n");
if(FAILED(hr = CoInitializeEx(NULL,tagCOINIT::COINIT_APARTMENTTHREADED)))
return ERROR_INVALID_DATA;
fwprintf(fp,L"did coinit\n");
if(FAILED(hr = pCon.CreateInstance(__uuidof(Connection))))
return ERROR_INVALID_DATA;
fwprintf(fp,L"created instance of connection\n");
TCHAR constr[1024];
DWORD constrlen = sizeof(constr);
rc=MsiGetProperty(hInstaller,TEXT("DBCONNECTIONSTRING"), constr, &constrlen);
fwprintf(fp, L"dbconstring is: %s\n", constr);
TCHAR serverstr[1024];
DWORD serverstrlen = sizeof(serverstr);
rc = MsiGetProperty(hInstaller,TEXT("SQLINSTANCE"),serverstr,&serverstrlen);
fwprintf(fp, L"SQLINSTANCE is: %sl\n",serverstr);
TCHAR finalconstr[2048];
swprintf(finalconstr,L"%s; Data Source=%s;",constr,serverstr);
try{
hr = pCon->Open(finalconstr,TEXT(""),TEXT(""),adConnectUnspecified);
}
catch(_com_error ce){
fwprintf(fp, L"%s\n", msg);
::MessageBox(NULL,msg,NULL,NULL);
CoUninitialize();
MsiSetProperty(hInstaller,TEXT("DBCONNECTIONVALID"),TEXT("0"));
return ERROR_SUCCESS;
}
if(FAILED(hr)){
MsiSetProperty(hInstaller,TEXT("DBCONNECTIONVALID"),TEXT("0"));
return ERROR_SUCCESS;
}
pCon->Close();
CoUninitialize();
MsiSetProperty(hInstaller,TEXT("DBCONNECTIONVALID"),TEXT("1"));
::MessageBox(NULL,TEXT("Successfully connected to the database!"),NULL,NULL);
fwprintf(fp, L"leaving...\n");
fclose(fp);
return ERROR_SUCCESS;
}
现在,当我将此函数构建到 dll 中并将其添加到我的 WiX 项目中时,此代码可以工作在我的开发计算机上(具体来说,安装成功完成,文件“dbcontestdll.txt”存在并且其中包含正确的数据) - 但是,当我在“全新安装”计算机上运行它时,安装失败并显示退出代码第2896章 没有创建“dbcontestdll.txt”。
在 Windows 安装程序中使用基于 C 的 dll(例如 C++ 可再发行组件)是否有先决条件?
I'm creating a WiX installer to install a program which connects to a database. To help with this, I've created a C dll which checks to see if a certain instance of SQL exists on a server:
extern "C" UINT __stdcall DBConTest(MSIHANDLE hInstaller)
{
FILE *fp;
fp = fopen("dbcontestdll.txt", "w");
_ConnectionPtr pCon;
int iErrCode;
HRESULT hr;
UINT rc;
//init COM
fwprintf(fp, L"entering dbcontest\n");
if(FAILED(hr = CoInitializeEx(NULL,tagCOINIT::COINIT_APARTMENTTHREADED)))
return ERROR_INVALID_DATA;
fwprintf(fp,L"did coinit\n");
if(FAILED(hr = pCon.CreateInstance(__uuidof(Connection))))
return ERROR_INVALID_DATA;
fwprintf(fp,L"created instance of connection\n");
TCHAR constr[1024];
DWORD constrlen = sizeof(constr);
rc=MsiGetProperty(hInstaller,TEXT("DBCONNECTIONSTRING"), constr, &constrlen);
fwprintf(fp, L"dbconstring is: %s\n", constr);
TCHAR serverstr[1024];
DWORD serverstrlen = sizeof(serverstr);
rc = MsiGetProperty(hInstaller,TEXT("SQLINSTANCE"),serverstr,&serverstrlen);
fwprintf(fp, L"SQLINSTANCE is: %sl\n",serverstr);
TCHAR finalconstr[2048];
swprintf(finalconstr,L"%s; Data Source=%s;",constr,serverstr);
try{
hr = pCon->Open(finalconstr,TEXT(""),TEXT(""),adConnectUnspecified);
}
catch(_com_error ce){
fwprintf(fp, L"%s\n", msg);
::MessageBox(NULL,msg,NULL,NULL);
CoUninitialize();
MsiSetProperty(hInstaller,TEXT("DBCONNECTIONVALID"),TEXT("0"));
return ERROR_SUCCESS;
}
if(FAILED(hr)){
MsiSetProperty(hInstaller,TEXT("DBCONNECTIONVALID"),TEXT("0"));
return ERROR_SUCCESS;
}
pCon->Close();
CoUninitialize();
MsiSetProperty(hInstaller,TEXT("DBCONNECTIONVALID"),TEXT("1"));
::MessageBox(NULL,TEXT("Successfully connected to the database!"),NULL,NULL);
fwprintf(fp, L"leaving...\n");
fclose(fp);
return ERROR_SUCCESS;
}
Now, when I build this function into a dll and add it to my WiX project, this code works on my development machine (specifically, the installation successfully finishes and the file "dbcontestdll.txt" exists and has the correct data in it)--but, when I run it on a "fresh install" machine, the installation fails with exit code 2896 and the "dbcontestdll.txt" is not created.
Are there prerequisites to using C-based dlls in a Windows Installer, such as the C++ redistributable?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
对于自定义操作,我强烈建议静态链接到 C 运行时。自定义 aciton DLL 最终会更大一些,但您对自定义操作之外的文件的依赖性会减少。
For custom actions, I highly recommend statically linking to the C run time. The custom aciton DLL ends up a little bigger but you'll have one less dependency on files outside the custom action.
是的,您可能需要 Visual C 运行时。 Dependency Walker 可能会帮助查找所需的 dll。
查看此示例,了解如何使用 Bootstrapper。这样您就可以在运行 msi 之前安装运行时。我使用以下引导程序行:
此包通常存储在
C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bootstrapper\Packages\vcredist_x86
目录中。Yes you probably need the visual c runtime. Dependency Walker might assist finding the required dlls.
Look at this example how to use a Bootstrapper. This way you can install the runtime before the msi will be run. I use the following bootstrapper line:
This package is normally stored in the
C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bootstrapper\Packages\vcredist_x86
directory.我也有这个问题。我有一个默认情况下动态链接的 MFC DLL,但我忘记在包中包含 MSVCR100.DLL。当然,它在开发机器上运行良好,甚至在大多数客户的机器上运行良好,但在旧的 Vista PC 上却失败了。我切换到静态链接。
I had this problem also. I had an MFC DLL that was dynamically linking by default, and I forgot to include MSVCR100.DLL in the package. Of course it worked fine on the development machine, it even worked on most customers' machines, but it failed on an old Vista PC. I switched to statically linked.
您可能不希望自己陷入必须引导 C++ redist 才能运行自定义操作的情况。您是否尝试过使用文件 |新 | WiX 附带的 C++ 自定义操作对象?您可以使用它来删除您的 CA,然后将代码复制并粘贴到其中。这应该为您提供避免此问题所需的所有编译器和链接器设置。
You probably don't want to get yourself into the situation where you have to bootstrap C++ redists just to run a Custom Action. Have you tried using the File | New | C++ Custom Action probject that comes with WiX? You can use that to stub out your CA and then copy and paste your code into it. That should give you all the compiler and linker settings that you need to avoid this problem.