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

为什么缺少类型信息的UDT/struct会导致vb6中的静默启动失败?,struct,com,vb6,midl,typelib,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 C

在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
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
当我从类型库中删除结构并重新编译它时,以前编译的a.exe仍然有效,即使结构定义不再存在。我假设这是成功的,因为定义在vb6编译过程中嵌入到可执行文件中

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

Private Sub Command1_Click()

Dim obj As structLib.MyStruct

obj.m_sStr = "Hello"
MsgBox obj.m_sStr 

End Sub
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
请注意将结构赋值给
变量

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

  • 启动可执行文件将加载表单
  • 单击该按钮会引发错误,因为将缺少类型信息的结构分配给
    变量
为了记录在案,我尝试在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);
structLib::MyStruct obj;
obj.m_sStr=SysAllocString(L“Hello”);
MessageBox(GetActiveWindow(),obj.m_sStr,obj.m_sStr,MB_OK);
ATL::CComVariant vtRec;
ATL::CComPtr piRecInfo;
HRESULT hr=GetRecordInfoFromGuids(uuuIdof(structLib::uuuuStructLib),1,0,0,uuuuIdof(structLib::MyStruct),&piRecInfo);
vtRec.pRecInfo=piRecInfo;
vtRec.pvRecord=&obj;
PVOID pvItem=vtRec.pvRecord;
变异vTSR;
hr=piRecInfo->GetField(pvItem,L“m_sStr”和&vtStr);
MessageBox(GetActiveWindow(),vtStr.bstrVal,vtStr.bstrVal,MB_OK);

这里,C++客户端运行和<代码> GETReCordIfFROMGuuthSub()/Cuth>正确返回

0x8002802b(未找到元素)

当类型库中缺少结构定义时

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

vb6中的这种行为是设计的吗

我不这么认为

原因是什么

将IDL结构分配给变量时,本质上使用[uuid]属性。因为它已经不存在了,你会得到一个例外

这是您在C++中调用<代码> GETReCordFIOFROMGUIDs 时所做的,您可以明确地提供IDL结构的代码UUID:Cuth.O.UuIDOF(StultLIb::MyStult)

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

我认为实现这一目标有两种可能性:

  • 使用后期绑定而不是早期绑定,并检查引用
  • 处理引发的异常

  • 谢谢你的建议,不过我的问题是指vb6可执行文件。问题是vb6可执行文件(b.exe)无法运行;可能是因为代码仍然包含获取已删除结构的类型信息的指令。这不会给我任何机会发现错误。至于后期绑定,我认为不可能在没有具体类型的情况下创建结构实例。VB6/a中对此有一个定义。这是一个编译时错误,因此如果您解决了它,那么程序崩溃也就不足为奇了。实际上,我不介意由于UDT的类型信息缺失而出现错误。困扰我的是vb6 exe甚至没有启动。这不应该发生,因为有问题的代码(
    vt=obj
    )位于命令按钮处理程序中,在加载表单期间不会执行该处理程序。我期望类似C++客户端的行为,其中代码运行直到提取类型信息(<代码> GETReCordIfFuffRebug Sub()/代码>),而这又报告了一个错误。C++中,开始时不是编译时错误。在VB中,这是一个编译时错误,如果你欺骗程序,任何事情都可能发生。确实奇怪的是,缺少UDT定义会导致完全启动失败。相反,被撤销的早期绑定COM接口的处理方式不同:代码在声明之前一直运行,然后报告运行时错误13(类型不匹配)。为什么这种行为不适用于UDT?