COM Record Support

# COM Record support in pywin32

The pywin32 package provides COM Record support for late-bound and early-bound objects. In both cases it is required that the Type Library which defines the COM Record has been registered in Windows.

## Late-bound objects

For late-bound objects, were makepy-support is not available, it is possible to create a particular COM Record if the following is known:

- GUID of the Type Library were the Record is defined
- Major version of the registered Type Library
- Minor version of the registered Type Library
- LCID of the registered Type Library
- GUID of the COM Record in this Type Library

An instance of the COM Record is created with `pythoncom.GetRecordFromGuids`, e.g.:

    import pythoncom

    PyCOMTestLib_GUID = '{6bcdcb60-5605-11d0-ae5f-cadd4c000000}'
    MAJVER = 1
    MINVER = 1
    LCID = 0
    TestStruct1_GUID = '{7a4ce6a7-7959-4e85-a3c0-b41442ff0f67}'

    record1 = pythoncom.GetRecordFromGuids(PyCOMTestLib_GUID, MAJVER, MINVER, LCID, TestStruct1_GUID)

The Python type of the returned COM Record instance is:

    >>> type(record1)
        <class 'com_record'>

which is a generic type that is returned for all COM Records, i.e. COM Records with different GUIDs nevertheless all have the same Python type `pythoncom.com_record`.

Instances of `<class 'com_record'>` can be used as method parameters and are returned by COM methods that return a COM Record. However, it is not possible to differentiate the COM Record Types, i.e. COM Records of different GUID at runtime.

## Early-bound objects

The availability of makepy-support does in its basic form offer the convenience function `win32com.client.Record` to create COM Record instances using the COM Record name from the Type Library and an interface object of the same Type Library:

    import win32com.client

    com_test = win32com.client.Dispatch("PyCOMTest.PyCOMTest")

    record1 = win32com.client.Record('TestStruct1' ,com_test)

Still the Python type of the returned COM Record instance is:

    >>> type(record1)
        <class 'com_record'>

i.e. the generic base type of all COM Records.

### Defining subclasses of `pythoncom.com_record`

It is possible to create subclasses of the base `pythoncom.com_record` type and register such a subclass for a particular COM Record type. As a prerequisite, it is mandatory for the subclass to define the following class attributes:

- TLBID : The GUID of the containing TypeLibrary as a string
- MJVER : The major version number of the TypeLibrary as an integer
- MNVER : The minor version number of the TypeLibrary as an integer
- LCID : The LCID of the TypeLibrary as an integer
- GUID : The GUID of the COM Record as a string

with GUID strings in {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} notation, e.g.:

    import pythoncom

    class TestStruct1(pythoncom.com_record):
      TLBID = '{6bcdcb60-5605-11d0-ae5f-cadd4c000000}'
      MJVER = 1
      MNVER = 1
      LCID = 0
      GUID = '{7a4ce6a7-7959-4e85-a3c0-b41442ff0f67}'

Before this subclass can be used to create TestStruct1 instances, it has to be registered with `win32com.client.register_record_class`, e.g.:

    from win32com.client import register_record_class

    register_record_class(TestStruct1)

With such a class, registered for a particular COM Record type, it is possible to identify the COM Record type at runtime:

    >>> record1 = TestStruct1()

    >>> type(record1)
        <class 'main.TestStruct1'>

Also COM methods that return a COM Record type for which a Python class was registered as described above, will return values of the proper Python class type, e.g.:

    >>> # Given the following definition in the Type Library IDL-file:
    >>> # HRESULT GetStruct([out, retval]TestStruct1 *ret);

    >>> retval = GetStruct()

    >>> type(retval)
        <class 'main.TestStruct1'>

COM methods that return a COM Record type for which no Python class was registered will continue to return values of the generic type `pythoncom.com_record`, e.g.:

    >>> # Given the following definition in the Type Library IDL-file:
    >>> # HRESULT GetOtherStruct([out, retval]AnotherStruct *ret);

    >>> retval = GetOtherStruct()

    >>> type(retval)
        <class 'com_record'>