【问题标题】:How do I return a unicode string / wstring / CStringW from a C++ dll to InstallScript?如何将 unicode 字符串 / wstring / CStringW 从 C++ dll 返回到 InstallScript?
【发布时间】:2015-07-03 23:03:07
【问题描述】:

我正在使用 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 功能。

【问题讨论】:

  • 你的函数的调用约定是stdcall?
  • 您可以先创建一个使用您的.dll 函数的虚拟应用程序。还要确保您的 .dll 遵守 InstallShield 强加的约定。

标签: c++ string dll installshield installscript


【解决方案1】:

感谢大家的帮助!不过,我终于自己弄清楚了。但是,该解决方案有多个方面,我没有在其他地方找到文档或建议。

要点

1) 从 C++ 返回一个 WCHAR *

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

3) 将其返回到 InstallScript 中的常规 STRING 变量中,并像对待任何其他变量一样对待它

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

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


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

安装脚本

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

【讨论】:

    【解决方案2】:

    当您可以使您的界面使用 C 方法而不是 C++ 方法时,您将获得最佳效果。匹配GetEnvironmentVariable 之类的函数接口,其中您的函数接受指向缓冲区的指针(并且为了正确起见,该缓冲区的大小),然后写入该缓冲区。您的大部分实现不必更改,只要您可以将 CString 中的 StringCchCopy 之类的内容放入缓冲区即可。

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

    剩下的就是声明这个供 InstallScript 使用。这意味着原型应该使用WSTRINGBYREF。如果函数接口和GetEnvironmentVariableW一样,原型应该是这样的:

    prototype MyFunc(WSTRING, BYREF WSTRING, NUMBER);
    

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

      • 您会将其返回到 InstallShield 端的哪种类型? (您想要操作并与其他 IS 字符串组合的原型和实际字符串?)
      猜你喜欢
      • 2020-05-08
      • 2021-12-01
      • 2011-03-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-04
      • 2018-03-08
      • 1970-01-01
      相关资源
      最近更新 更多