我如何 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/
我正在使用 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/