Использование COM-DLL с параметрами BSTR* -> ошибка Float Div By Zero
В настоящее время я разрабатываю собственное приложение среднего размера, которое должно включать некоторые функции, которые уже были включены в предыдущее приложение. Это было разработано в Visual Basic 6 много лет назад внешним поставщиком. К сожалению, у меня нет доступа к исходному коду, но, к счастью, необходимые классы содержатся в COM DLL, которая также была создана в VB6. В настоящее время используется среда разработки C++ Builder 10.1. Я могу легко установить DLL через regsvr32.exe. Функция импорта библиотеки типов в CBuilder сгенерировала красивую оболочку VCL на основе TOleServer. DLL довольно большая, и после импорта уже возникла проблема с отсутствующей перегрузкой функции, которую мне пришлось добавить вручную. Иначе оболочка вроде бы работает.
Теперь к настоящей проблеме:
DLL содержит класс, поля которого можно загрузить из файла XML с помощью метода Load. Эта функция имеет 2 параметра: Файл в виде строки и Схема в виде строки в VB6 и VBA (проверено в Excel 2010). Параметр Schema является необязательным. Если я сейчас создаю объект класса в VBA, я могу передать строку имени файла в качестве параметра File, и поля класса загружаются без проблем. Если я посмотрю на сгенерированный класс-оболочку в CBuilder, у функции Load есть два параметра типа "BSTR *". Параметр Schema помечается как необязательный в автоматически сгенерированном комментарии, но ему не назначено значение по умолчанию, и поэтому он не является обязательным (?). Поэтому я должен использовать параметр Схема. Странно, но вместо BSTR ожидается указатель на BSTR. Поэтому я попробовал следующее:
BSTR File = SysAllocString(L"C:\\temp\\file.xml");
BSTR Schema = SysAllocString(L"");
TMyOleClass *MyClass = new TMyOleClass(this);
MyClass->Load(&File, &Schema);
Поскольку файлы схемы обычно не используются, у меня их нет. Поэтому это нулевая строка.
Класс создается без ошибок, но функция Load выдает ошибку Float Divide By Zero в MSVBVM60.dll. Другие функции класса, для которых требуется обычный BSTR (не указатель на него), работают без проблем.
Так...
- Почему второй параметр не является обязательным в сгенерированной оболочке VCL?
- Почему параметры типа BSTR *, а не типа BSTR, как и другие?
- Почему указанная ошибка?
Спасибо за все ответы.
РЕДАКТИРОВАТЬ:
Я открыл класс с oleview.exe. Функция Load имеет следующее определение:
HRESULT Load(
[in, out] BSTR* Filepath,
[in, out, optional] BSTR* Schema,
[out, retval] VARIANT* );
хотя только в каталоге объектов Excel VBA
Function Load(Filepath As String, [Schema As String])
показано (нет ссылок).
Идея установить для параметра схемы значение NULL не сработало. Появилась та же ошибка div.
Благодаря @Remy Lebeau я создал вариант и попробовал снова:
BSTR Path = SysAllocString(L"C:\\temp\\file.xml");
VARIANT varOpt;
varOpt.vt = VT_ERROR;
varOpt.scode = DISP_E_PARAMNOTFOUND;
TC_MyClass *MyClass = new TC_MyClass(this);
MyClass->Load(&Path, (BSTR*)&varOpt);
-> та же ошибка.
Я обнаружил, что если пропустить Исключения с продолжением в 3 раза, появится ошибка: этот массив исправлен или временно заблокирован.
Ниже приведены некоторые картинки;
Строка кода в utilcls.h после этого поднимается ошибка
Вот некоторые части созданного CBuilder VCL-Wrapper:
class PACKAGE TC_MyClass : public Vcl::Oleserver::TOleServer
{
_C_MyClassPtr m_DefaultIntf;
_di_IUnknown __fastcall GetDunk();
public:
__fastcall TC_MyClass(System::Classes::TComponent* owner) : Vcl::Oleserver::TOleServer(owner)
{}
...
VARIANT __fastcall Load(BSTR* Filepath/*[in,out]*/, BSTR* Schema/*[in,out,opt]*/)
{
VARIANT Param3;
OLECHECK(GetDefaultInterface()->Load(Filepath, Schema, (VARIANT*)&Param3));
return Param3;
}
...
@ Реми Лебо: функция, которую мне пришлось изменить вручную, была
HRESULT __fastcall set_Sections(MyHugeAndComplex_dll_tlb::_E_SectionsPtr* Param1/*[in,out]*/)
{
return set_Sections((MyHugeAndComplex_dll_tlb::_E_Sections*)Param1/*[in,out]*/);
}
где мне пришлось добавить вторую реализацию
HRESULT __fastcall set_Sections(MyHugeAndComplex_dll_tlb::_E_SectionsPtr** Param1/*[in,out]*/)
{
return set_Sections(Param1/*[in,out]*/);
}
а также мне пришлось добавить его для второй функции:
HRESULT __fastcall set_Document(Msxml2_tlb::IXMLDOMDocument2Ptr* Param1/*[in,out]*/)
{
return set_Document((Msxml2_tlb::IXMLDOMDocument2*)Param1/*[in,out]*/);
}
РЕДАКТИРОВАТЬ 2:
Я создал VI в LabVIEW, который создает экземпляр класса и может без проблем вызывать функцию "Загрузка".
Теперь, когда оборачиваем сам этот созданный ВП в новую DLL-библиотеку Win32 с экспортированным вызовом функции-оболочки "Загрузить" и открываем эту DLL с помощью кода в CBuilder с помощью вызова "SafeLoadLibrary", возникает та же ошибка с плавающей запятой, даже когда я жестко программирую путь к XML в LabVIEW-VI. Я могу вызывать функцию "Загрузка" почти везде, кроме C++ Builder. Думая о том, может быть, это ошибка в CBuilder, а не моя вина...
String DLL_FileName = ExtractFilePath(Application->ExeName) + "MyNewCreatedDLLWrapper.dll";
HINSTANCE hInstance = (HINSTANCE)SafeLoadLibrary(DLL_FileName.w_str());
if(!hInstance)
throw(Exception("Error loading DLL"));
Load = (Load_Ptr)GetProcAddress(hInstance,"Load");
int32_t Length = 1000;
uint8_t Array[1000];
int32_t RetVal = Load("", Array, &Length); // <-- path can be omitted as it is hard coded in DLL
FreeLibrary(hInstance);
1 ответ
Итак... Я наконец-то запустил его и запустил, благодаря предложению z32a7ul установить 2-й параметр на NULL и рекомендации Реми Лебо о проверке редактируемого вручную метода. Похоже, что сам этот отредактированный метод вызывается функцией Load. Это была моя ошибка, когда я думал о недостающей перегрузке, когда просто нужно было изменить параметр def на тип указателя. Наконец, мне пришлось установить второй параметр в NULL, как упоминалось выше, но косвенно:
BSTR Path = SysAllocString(L"C:\\temp\\file.xml");
BSTR Schema = NULL;
TC_MyClass *MyClass = new TC_MyClass(this);
MyClass->Load((BSTR*)&Path, (BSTR*)&Schema);
Спасибо за ваши ответы.