Reputation: 845
Currently, I'm developing a mid-sized in-house application, which should include some features that are already included in a previous application. This has been developed in Visual Basic 6 many years ago by an external supplier. Unfortunately I don't have access to the source code, but fortunately, the necessary classes are contained in a COM DLL, which was also created in VB6. The currently used development environment is C++ Builder 10.1. I can easily install the DLL via regsvr32.exe. The type library import function in CBuilder has generated a nice VCL wrapper based on TOleServer. The DLL is quite huge, and after the import there was already a problem with a missing function overload, which I had to add by hand. Otherwise, the wrapper seems to work.
Now to the real problem:
The DLL contains a class whose fields can be loaded from an XML file by a method called Load. This function has 2 parameters: File As String and Schema As String in VB6 and VBA (checked with Excel 2010). The parameter Schema is optional. If I now create a class object in VBA, I can pass a filename string as the File param and the class fields are loaded without problems. If I look at the generated wrapper class in CBuilder, the Load function has two parameters of the "BSTR *" type. The Schema parameter is marked as optional in the automatically generated comment, but has not assigned a default value and is therefore not optional (?). So I have to use the parameter Schema. Strangely, a pointer to BSTR is expected instead of BSTR. So I tried the following:
BSTR File = SysAllocString(L"C:\\temp\\file.xml");
BSTR Schema = SysAllocString(L"");
TMyOleClass *MyClass = new TMyOleClass(this);
MyClass->Load(&File, &Schema);
Since schema files are not normally used, I have none. Therefore it's a zero string.
The class is created without errors, but the Load function throws a Float Divide By Zero error in MSVBVM60.dll. Other class functions that require a normal BSTR (not a pointer to it) work without problems.
So...
Thanks for all answers.
EDIT:
I've opened the class with oleview.exe. The function Load has the following definition there:
HRESULT Load(
[in, out] BSTR* Filepath,
[in, out, optional] BSTR* Schema,
[out, retval] VARIANT* );
albeit in the Excel VBA Object Catalog only
Function Load(Filepath As String, [Schema As String])
is shown (no references).
The idea to set the schema Parameter to NULL didn't work. The same div error came up.
Thanks to @Remy Lebeau, I created a variant and tried it again:
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);
--> same error.
I've discovered, that if skipping the Exceptions with Continue for 3 times, an error comes up saying: This array is fixed or temporarily locked.
Below are some Pictures;
The code line in utilcls.h after that the error is being raised
Here are some parts of the CBuilder generated 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;
}
...
@Remy Lebeau: The function I had to change manually was
HRESULT __fastcall set_Sections(MyHugeAndComplex_dll_tlb::_E_SectionsPtr* Param1/*[in,out]*/)
{
return set_Sections((MyHugeAndComplex_dll_tlb::_E_Sections*)Param1/*[in,out]*/);
}
where I had to add a second implementation
HRESULT __fastcall set_Sections(MyHugeAndComplex_dll_tlb::_E_SectionsPtr** Param1/*[in,out]*/)
{
return set_Sections(Param1/*[in,out]*/);
}
and also I had to add it for a second function:
HRESULT __fastcall set_Document(Msxml2_tlb::IXMLDOMDocument2Ptr* Param1/*[in,out]*/)
{
return set_Document((Msxml2_tlb::IXMLDOMDocument2*)Param1/*[in,out]*/);
}
EDIT 2:
I've created a VI in LabVIEW which creates an instance of the class and which can call the 'Load' function without problems.
Now, when wrapping this created VI itself within a new Win32 DLL with an exported wrapper function call 'Load' and opening this DLL by code in CBuilder by a 'SafeLoadLibrary' call, the same floating point error occurs, even when I hard code the path to the XML in the LabVIEW-VI. I can call the 'Load' function from nearly everywhere, except for C++ Builder. Thinking about, if maybe it's a bug in CBuilder and not my fault...
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);
Upvotes: 1
Views: 911
Reputation: 845
So....I finally got it up and running, thanks to z32a7ul's proposal to set the 2nd Parameter to NULL and Remy Lebeau's advice of doing a check on the manually edited method. It seems, that this edited method itself is being called by the Load function. It was my fault in thinking of a missing overload where it was just needed to change a parameter def to a pointer type. Finally, I had to set the second param to NULL as mentioned above, but indirectly:
BSTR Path = SysAllocString(L"C:\\temp\\file.xml");
BSTR Schema = NULL;
TC_MyClass *MyClass = new TC_MyClass(this);
MyClass->Load((BSTR*)&Path, (BSTR*)&Schema);
Thanks for your answers.
Upvotes: 0