Wix C ++用于创建文件的自定义操作

时间:2015-03-13 16:18:55

标签: c# visual-c++ wix

以前我编写了一个C#Custom Action,它应该将Values Properties传递给安装程序并创建一些配置文件。自C#Custom操作完成以来,我的安装程序也依赖于.Net。删除.Net依赖关系的唯一方法是在C++中编写自定义操作。

我之前尝试转换为C ++的C#代码如下:

session.Log("Entering WriteFileToDisk");
string ipAddress = session["IPADDRESS"];
string productCode = session["ProductCode"];
string config_path = "C:\\SomeFolderToInstall\\";
string compression = session["COMPRESSION"];
string ssl = session["SSL"];
if (string.IsNullOrEmpty(compression))
{
      compression = "True"; //default true
}
if (string.IsNullOrEmpty(ssl))
{
      ssl = "False"; //default false
}
if (string.IsNullOrEmpty(ipAddress))
{
      ipAddress = "127.0.0.1";
}
string temp = @"
{{
      ""logpoint_ip"" : ""{0}"",
      ""compression"" : ""{1}"",
      ""ssl"": ""{2}"" 
}}";
string filePath = "C:\\SomeFolderToInstall\\lpa.config";
System.IO.FileInfo file = new System.IO.FileInfo(filePath);
file.Directory.Create(); // If the directory already exists, this method does nothing.
System.IO.File.WriteAllText(file.FullName, config);
System.IO.File.WriteAllText(config_path + "productcode.txt", productCode);
session.Log("Confile file is written");
session.Log("Product Code file is written");
return ActionResult.Success;

以上C#代码的Visual C ++代码如下:

#include "stdafx.h"    
UINT __stdcall WriteFileToDisk(MSIHANDLE hInstall)
{
    HRESULT hr = S_OK;
    UINT er = ERROR_SUCCESS;

    hr = WcaInitialize(hInstall, "WriteFileToDisk");
    ExitOnFailure(hr, "Failed to initialize");

    LPWSTR ip = NULL;
    hr = WcaGetProperty(L"IPADDRESS",&ip);
    ExitOnFailure(hr, "Failure in IPADDRESS");

    if(ip == L"" || ip == NULL)
    {
        ip = L"127.0.0.1";
    }
    WcaLog(LOGMSG_STANDARD, (PCSTR)ip);
    LPWSTR ssl = NULL;
    hr = WcaGetProperty(L"SSL",&ssl);
    ExitOnFailure(hr, "Failure in SSL");

    if(ssl == L"" || ssl == NULL)
    {
        ssl = L"False";
    }
    LPWSTR comp = NULL;
    hr = WcaGetProperty(L"COMPRESSION",&comp);
    ExitOnFailure(hr, "Failure in COMPRESSION");

    if(comp == L"" || comp == NULL)
    {
        comp = L"True";
    }

    WcaLog(LOGMSG_STANDARD, "Got the Parameters");
    char buffer[150];
    sprintf(buffer, "{\n\"ipaddress\": \"%s\",\n\"ssl\": \"%s\",\n\"compression\":\"%s\"\n}",ip,ssl,comp);
    WcaLog(LOGMSG_STANDARD, "Config Generated is : ");
    WcaLog(LOGMSG_STANDARD, buffer);

    HANDLE hFile;
    hFile = CreateFile(L"C://LogPointAgent//some_config.config",                // name of the write
                       GENERIC_WRITE,          // open for writing
                       0,                      // do not share
                       NULL,                   // default security
                       CREATE_NEW,             // create new file only
                       FILE_ATTRIBUTE_NORMAL,  // normal file
                       NULL);

     if (hFile == INVALID_HANDLE_VALUE) 
    { 
        WcaLog(LOGMSG_STANDARD, "Invalid Handle for Config File");
        ExitFunction();
    }
     BOOL bErrorFlag;
     DWORD dwBytesToWrite = (DWORD)strlen(buffer);
     DWORD dwBytesWritten = 0;
     bErrorFlag = WriteFile( 
                    hFile,           // open file handle
                    buffer,      // start of data to write
                    dwBytesToWrite,  // number of bytes to write
                    &dwBytesWritten, // number of bytes that were written
                    NULL);            // no overlapped structure


     if (FALSE == bErrorFlag)
    {
        WcaLog(LOGMSG_STANDARD, "Terminal failure: Unable to write to file.\n");
    }
    else
    {
        if (dwBytesWritten != dwBytesToWrite)
        {
            // This is an error because a synchronous write that results in
            // success (WriteFile returns TRUE) should write all data as
            // requested. This would not necessarily be the case for
            // asynchronous writes.
            WcaLog(LOGMSG_STANDARD, "Error: dwBytesWritten != dwBytesToWrite\n");
        }
        else
        {
            WcaLog(LOGMSG_STANDARD, "Wrote Config file Successfully");
        }
    }

      CloseHandle(hFile);
LExit:
    er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
    return WcaFinalize(er);
}

// DllMain - Initialize and cleanup WiX custom action utils.
extern "C" BOOL WINAPI DllMain(
    __in HINSTANCE hInst,
    __in ULONG ulReason,
    __in LPVOID
    )
{
    switch(ulReason)
    {
    case DLL_PROCESS_ATTACH:
        WcaGlobalInitialize(hInst);
        break;

    case DLL_PROCESS_DETACH:
        WcaGlobalFinalize();
        break;
    }

    return TRUE;
}

以下是Wix文件代码,用于从C ++自定义操作生成的dll中调用函数WriteFileToDisk

<Binary Id="SetupCA"  SourceFile="..\WixCustomActionCPP\bin\Release\WixCustomActionCPP.dll"/>
<CustomAction Id="WRITEFILETODISK" Execute="immediate" BinaryKey="SetupCA" DllEntry="WriteFileToDisk" />
<InstallExecuteSequence>
  <Custom Action="WRITEFILETODISK" Before="InstallFinalize">NOT Installed</Custom>
</InstallExecuteSequence>

使用命令msiexec /i installer.msi /l*v out.txt IPADDRESS="192.168.2.208"安装安装程序时,应该将config生成为:

{
"ip":"192.168.2.208",
"ssl":"False",
"compression":"True"
}

但它现在产生的是:

{
"ipaddress": "1",
"ssl": "",
"compression":""
}

这里的C ++代码有什么问题?任何帮助,将不胜感激。感谢。

1 个答案:

答案 0 :(得分:1)

看一下这个答案:

C++ Custom Action returns empty string

您似乎正在使用Ansi格式来获取Unicode字符串。

你似乎也在sprintf中混合了Unicode和Ansi。该代码应使用WCHAR和其他Unicode构造。忘记Ansi,忘记char和sprintf(使用wsprintf for Unicode),我认为VC ++构建仍然是Unicode。