2015-07-03 4 views
0

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

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

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

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

+0

соглашение о вызове вашей функции является STDCALL? – fassl

+0

Вы можете начать с создания фиктивного приложения, которое использует вашу функцию '.dll'. Также убедитесь, что ваш '.dll' соответствует соглашениям, которые устанавливает InstallShield. – CristiFati

ответ

1

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

Основные пункты

1) возвращают WChar * из C++

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

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

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

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


Визуальный Студия Защита файл

LIBRARY MyIsDllHelper 
EXPORTS 
    getSomeStringW @1 

C++ Header

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

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

Вам лучше всего использовать интерфейс 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

Какой тип вы могли бы вернуть на стороне InstallShield? (Как прототип, так и фактическая строка, которую вы хотите манипулировать и комбинировать с другими строками IS?) – BuvinJ

+0

Кроме того, я попытался вернуть литерал std :: string без успеха ... – BuvinJ

 Смежные вопросы

  • Нет связанных вопросов^_^