2

Consider this registered type library in a DLL:

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

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

In vb6 I can reference this type library and use the UDT / struct in a compiled exe (simple form with a button), named a.exe:

Private Sub Command1_Click()

Dim obj As structLib.MyStruct

obj.m_sStr = "Hello"
MsgBox obj.m_sStr 

End Sub

When I remove the struct from the type library and recompile it, the previously compiled a.exe still works, even though the struct definition is no longer present. I assume this succeeds because the definition is embedded into the executable during the vb6 compilation process.

However, things work differently when I compile the following vb6 code against the unmodified type library (struct included) into a new executable, named 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

Notice the assignment of the struct to a Variant.

When I remove the struct definition from the type library once again, recompile it, and try to run the previously compiled b.exe, the program silently fails as the form won't even show up. At minimum, I expected

  • Starting the executable loads the form.
  • Clicking the button throws an error, due to assigning the struct with missing type information to the Variant.

For the record, I have tried to reproduce this behavior in 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);

Here, the C++ client runs and GetRecordInfoFromGuids() correctly returns

0x8002802b (Element not found)

when the struct definition is missing in the type library.

Is this behavior in vb6 by design? What's the cause? And is it possible to start the vb6 executable and catch error information, even when extracting type information of a referenced struct fails?

Aurora
  • 1,334
  • 8
  • 21
  • There is a [separate error](http://stackoverflow.com/q/975982/11683) for that in VB6/A. It's a compile time error, so if you work around it, it's no surprise the program then crashes. – GSerg Feb 02 '17 at 20:24
  • I actually wouldn't mind getting an error due to the missing type information of the UDT. What bothers me is that the vb6 exe doesn't even start up. This shouldn't be happening, since the offending piece of code (`vt = obj`) is located in the command button handler, which isn't executed during loading of the form. I expected a behavior similar to the C++ client, where the code runs up until the extraction of the type info (`GetRecordInfoFromGuids()`), which in turn reports an error. – Aurora Feb 03 '17 at 09:37
  • In C++ it's not a compile time error to begin with. In VB it is a compile time error, and anything can happen if you trick the program over it. – GSerg Feb 03 '17 at 12:21
  • It's indeed odd that a missing UDT definition leads to complete startup failure. In contrast, a revoked early bound COM interface is handled differently: the code runs up until the declaration, and then reports a run-time error 13 (Type mismatch). Why doesn't this behavior apply to UDTs as well? – Aurora Feb 03 '17 at 12:42

1 Answers1

0

Is this behavior in vb6 by design?

I don't think so.

What's the cause?

When you assign a IDL structure to a VARIANT, the [uuid] attribute is intrinsically used. As it doesn't exist anymore, you get an exception.

That's what you do when calling GetRecordInfoFromGuids in C++, you provide explicitely the uuid of the IDL structure __uuidof(structLib::MyStruct).

And is it possible to start the executable even when extracting type information of a referenced struct fails?

I see 2 possibilities to achieve this goal:

  1. use late binding instead of early binding, and check the reference
  2. handle the exception which is thrown
Jeandey Boris
  • 743
  • 4
  • 9
  • 1
    Thanks for your suggestions, however my questions were referring to the vb6 executable. The problem is that the vb6 executable (**b.exe**) fails to run; probably because the code still contains instructions to acquire type information of the deleted struct. This doesn't give me any chance to catch an error. As for late binding, I don't think it's possible to create an instance of a struct without a concrete type. – Aurora Feb 02 '17 at 20:11