为什么缺少类型信息的UDT / struct会导致vb6中的静默启动失败?

时间:2017-02-02 12:24:30

标签: struct com vb6 midl typelib

在DLL中考虑这个注册类型库:

[uuid(…), version(1.0)]
library structLib
{
    importlib("stdole2.tlb");

    [uuid(…)]
    typedef struct MyStruct
    {
        BSTR m_sStr;
    } MyStruct;
};

在vb6中,我可以引用这个类型库并在编译的exe(带有按钮的简单形式)中使用UDT / struct,名为 a.exe

Private Sub Command1_Click()

Dim obj As structLib.MyStruct

obj.m_sStr = "Hello"
MsgBox obj.m_sStr 

End Sub

当我从类型库中删除结构并重新编译它时,先前编译的 a.exe 仍然有效,即使结构定义不再存在。我认为这是成功的,因为在vb6编译过程中定义被嵌入到可执行文件中。

但是,当我将以下vb6代码针对未修改的类型库(包含struct)编译成名为 b.exe 的新可执行文件时,情况会有所不同:

Private Sub Command1_Click()

Dim obj As structLib.MyStruct

obj.m_sStr = "Hello"
MsgBox obj.m_sStr

Dim vt as Variant
vt = obj
MsgBox vt.m_sStr

End Sub

请注意将结构分配给Variant

当我再次从类型库中删除结构定义,重新编译它,并尝试运行以前编译的 b.exe 时,程序默默地失败,因为表单甚至不会显示。至少,我预计

  • 启动可执行文件加载表单。
  • 由于将缺少类型信息的结构分配给Variant,因此单击该按钮会引发错误。

为了记录,我试图在C ++中重现这种行为:

structLib::MyStruct obj;
obj.m_sStr = SysAllocString(L"Hello");

MessageBox(GetActiveWindow(), obj.m_sStr, obj.m_sStr, MB_OK);

ATL::CComVariant vtRec;     
ATL::CComPtr<IRecordInfo> piRecInfo;            
HRESULT hr = GetRecordInfoFromGuids(__uuidof(structLib::__structLib), 1, 0, 0, __uuidof(structLib::MyStruct), &piRecInfo);
vtRec.pRecInfo = piRecInfo;
vtRec.pvRecord = &obj;      

PVOID pvItem = vtRec.pvRecord;    
CComVariant vtStr;
hr = piRecInfo->GetField(pvItem, L"m_sStr", &vtStr);
MessageBox(GetActiveWindow(), vtStr.bstrVal, vtStr.bstrVal, MB_OK);

此处,C ++客户端运行并且GetRecordInfoFromGuids()正确返回

  

0x8002802b(找不到元素)

当类型库中缺少struct定义时。

这种行为是否符合vb6设计?原因是什么?是否有可能启动vb6可执行文件并捕获错误信息,即使提取引用结构的类型信息失败也是如此?

1 个答案:

答案 0 :(得分:0)

  

这种行为是否在vb6中设计?

我不这么认为。

  

原因是什么?

将IDL结构分配给VARIANT时,本质上会使用[uuid]属性。由于它不再存在,你得到一个例外。

在C ++中调用GetRecordInfoFromGuids时所执行的操作,您明确提供了IDL结构__uuidof(structLib::MyStruct)的uuid。

  

即使在提取类型时也可以启动可执行文件   引用结构的信息失败了吗?

我看到了实现这一目标的两种可能性:

  1. 使用后期绑定而不是早期绑定,并检查参考
  2. 处理抛出的异常