我如何 return unicode string / wstring / CStringW 从 C++ dll 到 InstallScript?

How do I return a unicode string / wstring / CStringW from a C++ dll to InstallScript?

我正在使用 InstallShield 2013 Premium。我在 Visual Studio 2010 年创建了一个 C++ dll,以提供一些我无法单独使用 InstallScript 实现的功能。我的 C++ 函数需要 return 一个小字符串(用户名)到 InstallScript 在做了大量工作后才能获得这个值。

在整个 C++ 中,我都使用 CStringW 来表示我的字符串。理想情况下,我想 return 它作为 Unicode,但如果这是我唯一的选择,我对 ANSI 很满意。我用 CStringW、std::wstring、std::string、LPCTSTR、LPSTR、char * 尝试了多种方法...我尝试直接 returns,并尝试通过引用 return。没有任何效果!

有时 dll 函数会挂起,有时会抛出异常,充其量是 return 带有非打印字符的垃圾值。关于此的官方文档似乎并不准确(它对我不起作用!)。广泛的谷歌搜索和搜索 Flexera 板从其他人那里得到 "solutions" 与同样荒谬的问题作斗争,但这些对我都不起作用......

直到最后我才尝试这个,因为我理所当然地认为你可以很容易地在 dll 和 InstallScript 之间传递字符串。回想起来,我应该从两者的接口开始,然后再开发dll功能。

当您可以使您的界面使用 C 方法而不是 C++ 方法时,您的状态最好。将 CString 中的 GetEnvironmentVariable in which your function accepts a pointer to a buffer (and for correctness a size of that buffer), and then writes into that buffer. The majority of your implementation shouldn't have to change, as long as you can finish with something like a StringCchCopy 等函数的接口匹配到缓冲区中。

既然你特别提到了 CStringW 和其他 Unicode 字符串类型,我建议选择 LPWSTR(而不是 LPTSTR)作为接口类型。

然后剩下的就是声明它以供 InstallScript 使用。这意味着原型应该使用 WSTRING and BYREF。如果函数接口与GetEnvironmentVariableW相同,原型应该是这样的:

prototype MyFunc(WSTRING, BYREF WSTRING, NUMBER);

感谢大家的帮助!不过,我终于自己弄明白了。然而,解决方案有多个方面,我没有在其他地方找到记录或建议。

要点

1) return 来自 C++ 的 WCHAR *

2) 使用 WSTRING 作为 InstallScript 原型中相应的 return 类型

3) return 将其放入 InstallScript 中的常规 STRING 变量,并像对待任何其他变量一样对待它

4) 将WCHAR * 指向的值保留在静态变量中的C++ dll 中,否则它显然会被删除并且指针变得无效

如果你已经走得够远发现自己在同一条船上,我可能不需要提供每一个细节,但这里有一大块示例代码可以帮助你:


Visual Studio 定义文件

LIBRARY MyIsDllHelper
EXPORTS   
   getSomeStringW   @1

C++ 头文件

#ifdef MYISDLLHELPER_EXPORTS
#define MYISDLLHELPER_API __declspec(dllexport) 
#else
#define MYISDLLHELPER_API __declspec(dllimport) 
#endif

#include <stdexcept>
#include <atlstr.h>

namespace MyIsDllHelper
{
    class MyIsDllHelper
    {
    public:         
    static MYISDLLHELPER_API WCHAR * getSomeStringW();
    };
}

C++ 源代码

#include "stdafx.h"
#include "MyIsDllHelper.h"

static CStringW someStringRetained;

CStringW getTheString()
{
    CStringW s;
    // do whatever...

    return s;
} 

WCHAR * MyIsDllHelper::MyIsDllHelper::getSomeStringW()
{   
    someStringRetained = getTheString();
    return someStringRetained.GetBuffer( someStringRetained.GetLength() ) + L'[=12=]';
}

安装脚本

#define HELPER_DLL_FILE_NAME "MyIsDllHelper.dll"
prototype WSTRING MyIsDllHelper.getSomeStringW();

function DoSomething( hMSI )
    STRING svSomeString;    
    STRING svDllPath;   
begin

    // Find the .dll file path. (A custom function)
    GetSupportFilePath( HELPER_DLL_FILE_NAME, TRUE, svDllPath );    

    // Load the .dll file into memory.
    if( UseDLL( svDllPath ) != 0 ) then
        MessageBox ("Could not load dll: " + svDllPath, SEVERE );
        abort;
    endif;

    // Get the string from the dll 
    try         
        svSomeString = MyIsDllHelper.getSomeStringW();
    catch   
        MessageBox( "Could not execute dll function: MyIsDllHelper.getSomeStringW", SEVERE );
        abort;      
    endcatch;       

    // Remove the .dll file from memory.
    if( UnUseDLL( svDllPath ) < 0 ) then
        MessageBox ("Could not unload dll: " + svDllPath, SEVERE );
        abort;
    endif;

    // Use the string
    MessageBox( "svSomeString: [" + svSomeString + "]", INFORMATION );       

end;

你可以使用字符串,但我想问题出在编码上。

看这里:https://adventuresinscm.wordpress.com/2014/01/12/unicode-files-and-installshield/