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

问题描述:

在DLL中考虑这个注册类型库:为什么UDT /结构中缺少类型信息导致vb6中的静默启动失败?

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

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

在VB6我可以引用这种类型的库,并使用在编译的exe的UDT /结构(简单的形式与一个按钮),命名为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(包括结构)到一个新的可执行文件,命名为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 

通知struct的分配到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(找不到元素)

当类型库中的结构定义丢失时。

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

+0

异常有一个[单独的错误](http://*.com/q/975982/11683)在VB6/A中。这是一个编译时错误,所以如果你解决它,那么程序就会崩溃并不奇怪。 – GSerg

+0

我其实并不介意因UDT的遗漏类型信息而发生错误。令我困扰的是vb6 exe甚至没有启动。这不应该发生,因为有问题的一段代码('vt = obj')位于命令按钮处理程序中,该处理程序在加载表单期间未执行。我期望的行为类似于C++客户端,代码运行直到提取类型信息('GetRecordInfoFromGuids()'),而后者又报告错误。 – Aurora

+0

在C++中,开始时不是编译时错误。在VB中,这是一个编译时错误,如果你通过它欺骗程序,任何事情都可能发生。 – GSerg

这是行为在vb6设计?

我不这么认为。

原因是什么?

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

这是调用C++ GetRecordInfoFromGuids当你做什么,你明确地提供的IDL结构__uuidof(structLib::MyStruct)的UUID。

即使提取类型为 的信息,也可以启动可执行文件吗?

我看到2种可能性,以实现这一目标:

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

感谢您的建议,但我的问题是指vb6可执行文件。问题是vb6可执行文件(** b.exe **)无法运行;可能是因为代码仍然包含获取已删除结构的类型信息的指令。这并不能让我有机会发现错误。至于后期绑定,我不认为有可能创建一个没有具体类型的结构的实例。 – Aurora