如何将C++dll中的unicode字符串/wstring/CStringW返回到InstallScript

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

本文关键字:wstring CStringW InstallScript 返回 字符串 C++dll 中的 unicode      更新时间:2023-10-16

我使用的是InstallShield 2013 Premium。我在Visual Studio 2010中创建了一个C++dll,以提供一些单独使用InstallScript无法实现的功能。我的C++函数需要在完成大量工作后向InstallScript返回一个小字符串(用户名(来获得这个值。

在整个C++中,我使用CStringW来表示我的字符串。理想情况下,我希望将其返回为Unicode,但如果这是我唯一的选择,我对ANSI感到满意。我尝试过许多CStringW、std::wstring、std::string、LPCTSTR、LPSTR、char*。。。我尝试了直接返回,并尝试通过引用返回。什么都不管用!

有时dll函数挂起,有时抛出异常,最多返回带有非打印字符的垃圾值。这方面的官方文件似乎不准确(对我来说不起作用!(。广泛的谷歌搜索和搜索Flexera董事会从其他人那里得到了解决同样荒谬问题的"解决方案",但这些对我来说也不管用。。。

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

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

要点

1( 从C++返回WCHAR*

2( 在InstallScript原型中使用WSTRING作为相应的返回类型

3( 将其返回到InstallScript中的常规STRING变量中,并将其视为任何其他

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

如果你已经走到了同一条船上,我可能不需要提供每一个细节,但这里有一大块示例代码可以帮助你:


Visual Studio Def文件

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'';
}

InstallScript

#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;

当您可以让您的接口使用C方法而不是C++方法时,您将处于最佳状态。匹配GetEnvironmentVariable等函数的接口,在该接口中,函数接受指向缓冲区的指针(为了正确起见,还接受该缓冲区的大小(,然后写入该缓冲区。只要您可以完成从CString到缓冲区的StringCchCopy之类的操作,那么您的大部分实现就不必更改。

由于您特别提到CStringW和其他Unicode字符串类型,我建议选择LPWSTR(而不是LPTSTR(作为接口类型。

然后剩下的就是声明这个供InstallScript使用。这意味着原型应该使用WSTRING和BYREF。如果函数接口与GetEnvironmentVariableW相同,那么原型应该如下所示:

prototype MyFunc(WSTRING, BYREF WSTRING, NUMBER);

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

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