使用带有 BSTR* 参数的 COM-DLL --> Float Div By Zero error

Using a COM-DLL with BSTR* parameters --> Float Div By Zero error

目前,我正在开发一个中等规模的内部应用程序,它应该包括以前的应用程序中已经包含的一些功能。这是多年前由外部供应商在 Visual Basic 6 中开发的。不幸的是我无权访问源代码,但幸运的是,必要的 classes 包含在一个 COM DLL 中,它也是在 VB6 中创建的。目前使用的开发环境是C++ Builder 10.1。我可以通过 regsvr32.exe 轻松安装 DLL。 CBuilder 中的类型库导入功能基于TOleServer 生成了一个很好的VCL 包装器。 DLL 非常大,导入后已经存在缺少函数重载的问题,我必须手动添加。否则,包装器似乎可以工作。

现在进入真正的问题:

DLL 包含一个 class,其字段可以通过名为 Load 的方法从 XML 文件加载。此函数有 2 个参数:File As StringSchema As String in VB6 和 VBA(使用 Excel 2010 检查).参数 Schema 是可选的。如果我现在在 VBA 中创建一个 class 对象,我可以传递一个文件名字符串作为 File 参数并且 class 字段加载没有问题. 如果我查看 CBuilder 中生成的包装器 class,Load 函数有两个 "BSTR *" 类型的参数。 Schema 参数在自动生成的注释中被标记为 optional,但没有分配默认值,因此不是可选的(?)。所以我必须使用参数Schema。奇怪的是,预期 指向 BSTR 的指针而不是 BSTR。所以我尝试了以下方法:

BSTR File = SysAllocString(L"C:\temp\file.xml");
BSTR Schema = SysAllocString(L"");

TMyOleClass *MyClass = new TMyOleClass(this);

MyClass->Load(&File, &Schema);

由于通常不使用架构文件,所以我有 none。因此它是一个字符串。

class 创建时没有错误,但是 Load 函数在 MSVBVM60.dll[= 中抛出 Float Divide By Zero 错误105=]。其他需要正常 BSTR(不是指向它的指针)的 class 函数可以正常工作。

所以...

  • 为什么第二个参数在生成的 VCL 包装器中不是可选的?
  • 为什么参数是 BSTR* 类型而不是 BSTR 类型?
  • 为什么会出现上述错误?

谢谢大家的回答。


编辑:

我用 oleview.exe 打开了 class。函数 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);

--> 同样的错误。

我发现,如果使用 Continue 跳过异常 3 次,则会出现错误消息:This array is固定或暂时锁定.

下面是一些图片;

The error (German BCB)

The code line in utilcls.h after that the error is being raised


以下是 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;
}  

...

@Remy Lebeau:我必须手动更改的功能是

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:

我在 LabVIEW 中创建了一个 VI,它创建了 class 的一个实例,并且可以毫无问题地调用 'Load' 函数。

现在,当使用导出的包装函数调用 'Load' 将这个创建的 VI 本身包装在一个新的 Win32 DLL 中并通过 'SafeLoadLibrary' 调用在 CBuilder 中通过代码打开这个 DLL 时,即使我在 LabVIEW-VI 中硬编码 XML 的路径,也会出现相同的浮点错误、。我几乎可以从任何地方调用 'Load' 函数, 除了 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);

所以....我终于搞定了 运行,感谢 z32a7ul 将第二个参数设置为 NULL 的建议以及 Remy Lebeau 对手动编辑的方法进行检查的建议。 看起来,这个编辑过的方法本身正在被 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);

感谢您的回答。