Я ищу самый безопасный способ передать логическую переменную VB6 в функцию (написанную в C++, stdcall).
Функция C++ установит переменную "bool" структуры, используя эту переменную VB6.
Я пробовал объявить это так в C++:
extern "C" __declspec(dllexport) int SetParameter( BOOL bErrorView)
{
DLL_sSettings nSet;
nSet.bErrorView =(bErrorView != FALSE);
int ret = stSetParameter(sizeof(DLL_sSettings), nSet);
return (ret);
}
stSetParameter объявляется как
extern "C" int ST_COMDLL_API stSetParameter(int DataLen, DLL_sSettings Settings);
DLL_sSetting объявляется как
typedef struct
{
bool bErrorView; // true: Show
// false: Don't show
(...)
} DLL_sSettings;
Однако я не могу заставить его работать.
Я называю это в VB6, используя
Private Declare Function SetParameter Lib "MyDLL.dll" Alias "_SetParameter@4" (ByVal bErrorView As Boolean) As Long
Но это работает не так, как ожидалось, я думаю, что где-то ошибка BBlean теряется или неправильно преобразуется.
В настоящее время я использую VB6 Boolean, C++ BOOL и C++ bool. Я знаю, что это не так хорошо, но я не вижу другого пути.
Кто-нибудь видит что-то неправильно в моем коде?
VB6 использует соглашение о вызове StdCall по умолчанию (соглашение cdecl поддерживается, если вы создаете библиотеку типов с секцией module
описывающей ваш импорт, вместо использования Declare Function
). И C++ поддерживает целый ряд соглашений о вызовах: stdcall, fastcall, cdecl, thiscall.
Важно отметить, что вызывающие функции, использующие stdcall в другой библиотеке, недостаточны для изменения ваших функций на stdcall. Вы можете использовать ключ командной строки для компилятора, но наиболее надежным является включение __stdcall
слова __stdcall
в исходный код. Он применяется к имени функции, например:
int __stdcall functionname(int args);
Поскольку вы также захотите экспортировать эти функции для VB6, чтобы найти их, вы хотите, чтобы extern "C"
уменьшил количество имен и __declspec(dllexport)
чтобы поместить их в таблицу экспорта.
Довольно часто использовать макрос для выполнения всего вышеперечисленного сразу. Похоже, что библиотека, которую вы обертываете, делает это с помощью ST_COMDLL_API
. Внутри библиотеки это расширится до __declspec(dllexport) __stdcall
. Для потребителей он будет использовать dllimport
вместо этого.
Каждый раз, когда вы определяете API, который будет использоваться в разных компиляторах (или даже на разных языках), неплохо быть очень явным в том, чтобы вызывать соглашение и упаковку структуры (#pragma pack
). В противном случае вы находитесь во власти опций, указанных в файле проекта и других файлах заголовков. Даже если вы довольны стандартами, которые использует компилятор, ваши публичные заголовки должны быть явными, поскольку в конечном итоге кто-то попытается использовать две библиотеки в одной программе, а другая библиотека может потребовать изменения параметров компиляции.
BOOL
- это определение типа для int
.
он объявил в windef.h следующим образом:
typedef int BOOL;
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
bool
- это тип C++, который нельзя использовать в прототипе функции, если вы объявляете функцию с помощью extern "C"
.
поэтому VB должен рассматривать BOOL как Long (32-битное целое число), а не как Bolean. 0 означает false в противном случае (обычно 1), это правда.
int
в интерфейсе и проверить, равен ли он 0 или нет.
SetParameter
stdcall.