Skip to content

Suggestion: Support functions for COM class & TypeLib registration #531

@forderud

Description

@forderud

This suggestion was originally proposed in microsoft/cppwinrt#1492, but the response was then to move the request to the WIL project.

BACKGROUND: I've just started modernizing some existing ATL projects to C++/WinRT. One challenge I then faced was lack of inbuilt support for registration of COM classes and type libraries. It would be very helpful if either WinRT or WIL could be extended with either support functions or sample code to demonstrate "best practice" in this area.

My "ask" is basically to add code resembling the RegisterTypeLibrary and RegisterComClass functions below to the repo.

Suggested code to add to the repo

/** COM type library (un)registration function. */
void RegisterTypeLibrary(bool do_register, std::wstring tlb_path) {
    if (do_register) {
        // register typelib
        CComPtr<ITypeLib> tlb;
        HRESULT hr = LoadTypeLibEx(tlb_path.c_str(), REGKIND_REGISTER, &tlb);
        assert(SUCCEEDED(hr));
    } else {
        // unregister typelib
        CComPtr<ITypeLib> tlb;
        HRESULT hr = LoadTypeLibEx(tlb_path.c_str(), REGKIND_NONE, &tlb);
        assert(SUCCEEDED(hr));

        TLIBATTR* attrPtr = nullptr;
        hr = tlb->GetLibAttr(&attrPtr);
        assert(SUCCEEDED(hr));

        UnRegisterTypeLib(attrPtr->guid, attrPtr->wMajorVerNum, attrPtr->wMinorVerNum, attrPtr->lcid, attrPtr->syskind); // will fail if already unregistered

        tlb->ReleaseTLibAttr(attrPtr);
    }
}

/** COM class (un)registration function. */
void RegisterComClass(bool do_register, CLSID clsid, ::GUID tlbGuid, std::wstring dll_exe_path) {
    std::wstring clsid_str(38, L'\0');
    int ret = StringFromGUID2(clsid, clsid_str.data(), static_cast<int>(clsid_str.size() + 1));
    assert(ret == 39); ret; // includes zero-termination

    if (do_register) {
        // register COM class
        std::wstring file_ext = dll_exe_path.substr(dll_exe_path.find_last_of(L'.'));

        if (!_wcsicmp(file_ext.c_str(), L".exe")) {
            std::wstring key_path = L"CLSID\\" + clsid_str + L"\\LocalServer32";
            CRegKey key;
            LSTATUS res = key.Create(HKEY_CLASSES_ROOT, key_path.c_str());
            assert(res == ERROR_SUCCESS); res;

            key.SetStringValue(nullptr, dll_exe_path.c_str());
        } else if (!_wcsicmp(file_ext.c_str(), L".dll")) {
            std::wstring key_path = L"CLSID\\" + clsid_str + L"\\InprocServer32";
            CRegKey key;
            LSTATUS res = key.Create(HKEY_CLASSES_ROOT, key_path.c_str());
            assert(res == ERROR_SUCCESS); res;

            key.SetStringValue(nullptr, dll_exe_path.c_str());
        } else {
            wprintf(L"ERROR: Unsupported file extension.\n");
            abort();
        }

        {
            std::wstring key_path = L"CLSID\\" + clsid_str + L"\\TypeLib";
            CRegKey key;
            LSTATUS res = key.Create(HKEY_CLASSES_ROOT, key_path.c_str());
            assert(res == ERROR_SUCCESS); res;

            wchar_t tlb_str[39] = {};
            StringFromGUID2(tlbGuid, tlb_str, static_cast<int>(std::size(tlb_str)));
            key.SetStringValue(nullptr, tlb_str);
        }
    } else {
        // unregister COM class
        CRegKey parent;
        LSTATUS res = parent.Open(HKEY_CLASSES_ROOT, L"CLSID", KEY_READ | KEY_WRITE);
        assert(res == ERROR_SUCCESS); res;

        parent.RecurseDeleteKey(clsid_str.c_str()); // will fail if already unregistered
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions