Как вернуть строку Unicode / wstring / CStringW из DLL C ++ в InstallScript?

Я использую InstallShield 2013 Premium. Я создал C ++ dll в Visual Studio 2010, чтобы обеспечить некоторую функциональность, которую я не смог бы достичь с помощью только InstallScript. Моя функция C ++ должна вернуть маленькую строку (имя пользователя) в InstallScript после значительной работы, чтобы получить это значение.

В C ++ я использую CStringW для представления своих строк. В идеале я хотел бы вернуть его как Unicode, но я доволен ANSI, если это мой единственный вариант. Я пробовал многочисленные подходы с CStringW, std :: wstring, std :: string, LPCTSTR, LPSTR, char * … Я пробовал прямой возврат и пытается вернуться по ссылке. Ничего не работает!

Иногда функция dll зависает, иногда выдает исключение, в лучшем случае возвращает значения мусора с непечатными символами. Официальная документация на это не кажется точной (она не работает для меня!). Обширный поиск в Google и поиск плат Flexera дают «решения» от других, борющихся с той же нелепой проблемой, и все же ни одна из них не работает и для меня …

Я не пробовал это до конца, так как считал само собой разумеющимся, что вы можете достаточно легко передавать строки между dll и InstallScript. Оглядываясь назад, я должен был начать с интерфейса между ними, а затем разработать dll-функциональность после этого.

0

Решение

Спасибо за помощь, ребята! Я наконец понял это для себя все же. Однако у этого решения есть несколько аспектов, которые я не нашел ни в документированном, ни в другом месте.

Основные моменты

1) вернуть WCHAR * из C ++

2) использовать WSTRING в качестве соответствующего возвращаемого типа в прототипе InstallScript

3) вернуть его в обычную переменную STRING в InstallScript и обработать как любую другую

4) сохранить значение, на которое указывает WCHAR * в dll C ++, в статической переменной, в противном случае оно, очевидно, удаляется и указатель становится недействительным

Если вы продвинулись достаточно далеко, чтобы оказаться в одной лодке, мне, вероятно, не нужно разбираться во всех деталях, но вот пример кода, который поможет вам в этом:


Visual Studio Def File

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 ++ Source

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

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

Другие решения

Лучше всего, когда вы можете заставить свой интерфейс использовать подходы C, а не C ++. Подходим интерфейс функций, таких как GetEnvironmentVariable в котором ваша функция принимает указатель на буфер (и для правильности размер этого буфера), а затем записывает в этот буфер. Большая часть вашей реализации не должна изменяться, если вы можете закончить с чем-то вроде StringCchCopy из вашей CString в буфер.

Поскольку вы специально упоминаете CStringW и другие типы строк Unicode, я бы предложил выбрать LPWSTR (скорее, чем LPTSTR) для типа интерфейса.

Тогда все, что осталось, это объявить это для использования с помощью InstallScript. Это означает, что прототип должен использовать WSTRING а также ByRef. Если интерфейс функции такой же, как GetEnvironmentVariableW, прототип должен выглядеть примерно так:

prototype MyFunc(WSTRING, BYREF WSTRING, NUMBER);
0

Вы можете использовать строки, но я думаю, что проблема с кодировкой.

Посмотрите здесь: https://adventuresinscm.wordpress.com/2014/01/12/unicode-files-and-installshield/

0
По вопросам рекламы [email protected]