Providing Type Information

The GetDynamicClassInfo method gives the host access to dynamic type information for the objects an ActiveX designer creates. You should implement this method if you expect any changes to the type information for the visual designer.

The method returns two parameters: ppTypeInfoOut, an indirect pointer to a type information object that describes a coclass; and pdwCookie, a handle that the host retains and saves in its own cache along with the type information.

The remainder of this section steps through tasks you may need to perform to create and return a dynamic type information object. Assume that the following declarations have been made:

ICreateTypeInfo *pctiDispinterface = NULL;
ICreateTypeInfo *pctiCoClass = NULL;
ICreateTypeLib2 *pCreateTypeLib = NULL;
ITypeInfo *ptiEvents = NULL, *ptiDispinterface;
HREFTYPE hreftype;
HRESULT  hr;

Error handling has been omitted for brevity throughout this section.

Creating the Type Library

The dynamic type information object must be in a new format type library.

To create a new type library, you use the ICreateTypeLib2 interface or the CreateTypeLib2 Application Programming Interface (API), as in the following example.

hr = CreateTypeLib2(SYS_WIN32, pwszFile, &pCreateTypeLib);

// Set the guid, helpstring DLL and name.
hr = pCreateTypeLib->SetGuid(m_state.guidTypeLib);
hr = pCreateTypeLib->SetHelpStringDll(L"");
hr = pCreateTypeLib->SetName(L"MyDesignerTypeLib");

In the example, pwszFile contains a temporary name for the type library and m_state is a global structure that holds useful information for the designer, including its GUID. You must set the name for the new type library.

Creating the Type Information Object

After creating the type library, you can create the type information object. The easiest way is to use an existing static type information object as a template. If the existing static object describes a virtual function table (VTBL) interface (or a dual interface), you can simply copy the object. Automation handles the necessary inheritance. You can then return an indirect pointer to your copy as the type information object (see "Returning Parameters," later in this section).

For a dispatch interface, however, the procedure is more complicated. You must copy the entire object and set up the inheritance yourself, in code. The following code fragment shows this procedure.

// Get the dispatch interface to use as a template.
hr = LoadRegTypeLib(*g_pLibid, (USHORT)VERSIONOFOBJECT(m_ObjectType),0,
            LANG_NEUTRAL, &pTypeLibStatic);

hr = pTypeLibStatic->GetTypeInfoOfGuid(DIID_DMyDesigner,
                                           &ptiDispinterface);
if (SUCCEEDED(hr)) {
    // Now get the type information of event interface.
    hr = pTypeLibStatic->GetTypeInfoOfGuid(
                        DIID_DMyDesignerEvents,ppTypeInfo);
    if (SUCCEEDED(hr)) {
        // And get the type information of control object.
        hr = pTypeLibStatic->GetTypeInfoOfGuid(CLSID_MyObject,                                     &m_state.pMyObjectTI);
    }
 }
pTypeLibStatic->Release();

The preceding code fragment gets an existing type information object that describes a dispatch interface. The next few lines create a new dispatch type information object and set its GUID. The local function _GetIDispatchTypeInfo returns the dispatch type information for the existing object. Calls to AddRefTypeInfo and AddImplTypeInfo set up the inheritance.

hr = pTypeLib->CreateTypeInfo(L"DMyDesignerObject", TKIND_DISPATCH,
                                  &pctiDispinterface);
hr = pctiDispinterface->SetGuid(m_state.guidTypeInfo);

hr = _GetIDispatchTypeInfo(&ptiDispatch);
hr = pctiDispinterface->AddRefTypeInfo(ptiDispatch, &hreftype);
hr = pctiDispinterface->AddImplType(0, hreftype);

Finally, the code copies the existing type information from *ptiDispInterface to the new object, *pctiDispInterface, and lays out the type information. In this example, CopyDispInterfaceTypeInfo is a local function that copies the information.

hr = CopyDispinterfaceTypeInfo(ptiDispinterface, pctiDispinterface);
pctiDispinterface->LayOut();
pctiDispinterface->AddRef();

At this point, pctiDispInterface points to a TKIND_DISPATCH type information object to be used as a template for the new dynamic type information object. The new object must contain type information for a coclass, so you have to create a blank object of TKIND_COCLASS:

hr = pCreateTypeLib->CreateTypeInfo(L"MyDesigner", TKIND_COCLASS,
                                    &pctiCoClass);

Next, you get the type information for the existing interfaces and events from the template in pctiDispinterface, add these to the new type information in ptiCoClass, and set the implementation type flags:

hr = pctiDispinterface->QueryInterface(IID_ITypeInfo,
                                           (void **)&ptiDispinterface);
// Information on the interface.
hr = pctiCoClass->AddRefTypeInfo(ptiDispinterface, &hreftype);
ptiDispinterface->Release();
hr = pctiCoClass->AddImplType(0, hreftype);

// Information on the events.
hr = pctiCoClass->AddRefTypeInfo(ptiEvents, &hreftype);
hr = pctiCoClass->AddImplType(1, hreftype);

// Now set up the flags for these two items.
hr = pctiCoClass->SetImplTypeFlags(0, IMPLTYPEFLAG_FDEFAULT);
hr = pctiCoClass->SetImplTypeFlags(1, IMPLTYPEFLAG_FDEFAULT
                                   | IMPLTYPEFLAG_FSOURCE);

When this is done, the type information object is set up. Only two tasks remain: setting up the output parameter and incrementing the cookie.

Returning Parameters

The ppTypeInfo output parameter of GetDynamicClassInfo is an indirect pointer to an ITypeInfo interface. Because pctiCoClass represents an ICreateTypeInfo interface, you have to query for the correct interface and cast the resulting pointer:

pctiCoClass->QueryInterface(IID_ITypeInfo, (void **)ppTypeInfo)

Finally, pass the current value of the cookie, which is stored in the global variable m_dwTICookie:

if (pdwCookie)
        *pdwCookie = m_dwTICookie;

The value of *pdwCookie is initially set in the InitNew or Load method of the designer's persistence interfaces, and is incremented if an unrecoverable error occurs when the persistent data are loaded.

When the host is reloaded, it checks the cookie to determine whether its cached version of the type information is up-to-date. If the cached version is accurate, the host can use it without having to reload the persistent state. If the cache is outdated, the host must reload the persistent state.