c++ - 使用带有 BSTR* 参数的 COM-DLL --> Float Div By Zero 错误

标签 c++ com c++builder vcl bstr

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

现在到真正的问题:

DLL 包含一个类,其字段可以通过称为 Load 的方法从 XML 文件中加载。此函数有 2 个参数:VB6 和 VBA 中的 File As String 和 Schema As String(使用 Excel 2010 检查)。参数 Schema 是可选的。如果我现在在 VBA 中创建一个类对象,我可以将文件名字符串作为文件参数传递,并且类字段的加载没有问题。
如果我查看 CBuilder 中生成的包装类,Load 函数有两个“BSTR *”类型的参数。 Schema 参数在自动生成的注释中被标记为可选,但没有分配默认值,因此不是可选的 (?)。所以我必须使用参数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 函数在 MSVBVM60.dll 中引发浮点除以零错误。其他需要普通 BSTR(不是指向它的指针)的类函数可以正常工作。

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

  • 感谢所有的答案。

    编辑:

    我已经用 oleview.exe 打开了类(class)。函数加载那里有以下定义:
    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 跳过 Exceptions 3 次,则会出现错误消息:此数组已修复或暂时锁定 .

    下面是一些图片;

    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,它创建了一个类的实例,并且可以毫无问题地调用“加载”函数。

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

    感谢您的回答。

    关于c++ - 使用带有 BSTR* 参数的 COM-DLL --> Float Div By Zero 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40690899/

    相关文章:

    c++ - "this"指针在堆栈跟踪中损坏

    c++ - 初始化字符矩阵时出现 EAccess 冲突

    c++ - Borland C++ Builder LoadFromResourceID 导致 EAccess 违规

    c++ - 找不到句首

    c++ - 糟糕的树添加性能

    events - PowerShell 2.0 是否支持 COM 事件处理程序?

    vba - 将早期绑定(bind)代码转换为后期绑定(bind)

    delphi - 如何阻止 Delphi 6 COM 服务器应用程序在启动时重新注册 COM

    delphi - "IS"CBuilder 中的运算符 Delphi

    c++ - 将正则表达式模式定义为无符号字符