【问题标题】:Using a COM-DLL with BSTR* parameters --> Float Div By Zero error使用带有 BSTR* 参数的 COM-DLL --> Float Div By Zero 错误
【发布时间】:2017-04-03 02:53:13
【问题描述】:

目前,我正在开发一个中型内部应用程序,其中应该包含一些已包含在以前的应用程序中的功能。这是多年前由外部供应商在 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 StringSchema As String(使用 Excel 2010 检查)。参数 Schema 是可选的。如果我现在在 VBA 中创建一个类对象,我可以将文件名字符串作为 File 参数传递,并且类字段的加载没有问题。 如果我查看 CBuilder 中生成的包装类,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);

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

类的创建没有错误,但 Load 函数在 MSVBVM60.dll 中引发 Float Divide By Zero 错误。其他需要普通 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);

-->同样的错误。

我发现,如果使用 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);

【问题讨论】:

  • 可能可选参数必须为 NULL,在这种情况下,与 Schema 相关的变量将被初始化为一些默认值。但是,因为您提供了一个空字符串,它会将变量初始化为零,而不是尝试解释 Schema;它失败了,因为它是一个空字符串,但是应用程序没有检测到这个错误,因为他们没有预料到它。然后稍后它会尝试在除法中使用浮点变量,例如纵横比 = 宽度/高度,但宽度和高度均为 0.0。
  • 相关参数的“入、出”属性是什么
  • 如果您发布 Load 函数的 IDL 定义以及自动生成的函数标头会有所帮助
  • 尝试将第二个参数设为NULL
  • 我现在在周末。我将在星期一回到我的工作机器时添加所需的信息。

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


【解决方案1】:

所以....我终于启动并运行了,这要感谢 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);

感谢您的回答。

【讨论】:

    猜你喜欢
    • 2011-07-03
    • 2017-01-20
    • 2017-03-17
    • 2022-11-17
    • 2019-01-16
    • 2011-02-12
    • 1970-01-01
    • 1970-01-01
    • 2011-06-29
    相关资源
    最近更新 更多