Thread overview
Experiments in early binding com object with D.
21 hours ago
Vinod K Chandran
21 hours ago
Dennis
18 hours ago
Vinod K Chandran
1 day ago

Hi all,
I was worrying that there is no com support except the basic building blocks like IUnknown and siblings. I know there is a com library in Adam's arsd. But I couldn't successfully use that. When I first tried Adam's library, I dreamed to write a com client in D one day. When time permitted, I slowly collected information about com and gradually made a confidence to start with early binding. I want to make my library high performance, so I choose early binding path.

There is a c++ example in this link which shows early binding to a known com server. But in that article, the author shows how to work with unknown servers using an IDL file.

So I collected the IDL file of MS Word and wrote a sample interface in D like this -

interface IWordApp : IDispatch
{
    HRESULT getApplication(IDispatch** prop);
    HRESULT getCreator(int* prop);
    HRESULT getParent(IDispatch** prop);
    ....
    HRESULT getUserName(BSTR* prop);
    HRESULT setUserName2( BSTR prop);
}

Then tried to print the Application.UserName with this code.

void getWordEarlyBinding() {
    const IID iid = {0x00020970, 0x0000, 0x0000,
                    [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]};
    const GUID clsid = {0x000209FF, 0x0000, 0x0000,
         [0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46]};


    IWordApp word;
    auto hr1 = CoInitializeEx(null, COINIT_APARTMENTTHREADED );
    auto cci_res = CoCreateInstance(&clsid, null,
                                        CLSCTX_LOCAL_SERVER,
                                        &iid, cast(void**)&word);

    if (FAILED(cci_res)) {
        writeln("CoCreateInstance failed for Word.Application");
    }
    scope(exit) word.Release();
    BSTR bstrUserName = null;
    auto hr = word.getUserName(&bstrUserName);
    scope(exit) SysFreeString(bstrUserName);
    if (SUCCEEDED(hr)) {
        writefln("Word User Name BSTR: %s", bstrUserName.to!string  );
    } else {
        writeln("Failed to get UserName property.");
    }

    CoUninitialize();
}

And this code worked. It just printed my user name on console. Is this approach safe ? Converting the IDL file entries to D interface is a herculean task. The article I said earlier shows a method to compile the IDL file with midl.exe and generate header file & tlb file. But I couldn't create that. So, either with the help of any AI tool, or a python script, I think we can convert the IDL file to a proper D interface. Or is there any better ways ? Let's discuss the possibilities of this.
Vinod Chandran.

1 day ago
Unfortunately COM is c++.

I have tried in the past to convert automatically but it is quite a hard task.

There is WinAPI functions to parse the files although I never figured out how to use it.

Just keep in mind that the layout of methods has to be exact when you convert them. You can't miss one.
21 hours ago

On Tuesday, 4 November 2025 at 04:55:15 UTC, Richard (Rikki) Andrew Cattermole wrote:

>

Unfortunately COM is c++.

I have tried in the past to convert automatically but it is quite a hard task.

There is WinAPI functions to parse the files although I never figured out how to use it.

Just keep in mind that the layout of methods has to be exact when you convert them. You can't miss one.

I appreciate your response. Yeah, COM is C++. Let me check the api functions to parse the IDL. And yeah, I just tested with interface and it must be aligned with the com vtbl. I think if we use dummy place holders, parameters and their types doesn't matter. In any case, I am confident that I can parse this idl file to a D interface.

21 hours ago

On Monday, 3 November 2025 at 16:51:25 UTC, Vinod K Chandran wrote:

>

I was worrying that there is no com support except the basic building blocks like IUnknown and siblings. I know there is a com library in Adam's arsd. But I couldn't successfully use that. When I first tried Adam's library, I dreamed to write a com client in D one day. When time permitted, I slowly collected information about com and gradually made a confidence to start with early binding. I want to make my library high performance, so I choose early binding path.

I have succesfully made a D program connect to Excel using arsd.com last year. My strategy was to ask ChatGPT to give examples using Python win32com and then translate those calls to D by sometimes adding extra parenthesis (because of limitations of @property / opDispatch). The resulting code looks something like this:

const choice = cell.Value().getD!string.ifThrown!Exception("");

// ...

auto c1 = sheet.Cells()(varsRow + i, varsValueColumn);
c1.Formula() = "=" ~ cs;
c1.Interior().Color() = color;

It's using the dynamic IDispatch interface instead of static bindings, which might be slower, but most calls take milliseconds to complete anyways and I highly doubt that all that time is spent on dynamic dispatch. The COM bridge and MS Office applications seem to be the limiting factor.

I recommend to start with dynamic calls and maybe create bindings from idl files later. If you explain what went wrong using arsd.com maybe I or someone else can help.

18 hours ago

On Tuesday, 4 November 2025 at 10:27:13 UTC, Dennis wrote:

>

On Monday, 3 November 2025 at 16:51:25 UTC, Vinod K Chandran wrote:

>

I was worrying that there is no com support except the basic building blocks like IUnknown and siblings. I know there is a com library in Adam's arsd. But I couldn't successfully use that. When I first tried Adam's library, I dreamed to write a com client in D one day. When time permitted, I slowly collected information about com and gradually made a confidence to start with early binding. I want to make my library high performance, so I choose early binding path.

I have succesfully made a D program connect to Excel using arsd.com last year. My strategy was to ask ChatGPT to give examples using Python win32com and then translate those calls to D by sometimes adding extra parenthesis (because of limitations of @property / opDispatch). The resulting code looks something like this:

const choice = cell.Value().getD!string.ifThrown!Exception("");

// ...

auto c1 = sheet.Cells()(varsRow + i, varsValueColumn);
c1.Formula() = "=" ~ cs;
c1.Interior().Color() = color;

It's using the dynamic IDispatch interface instead of static bindings, which might be slower, but most calls take milliseconds to complete anyways and I highly doubt that all that time is spent on dynamic dispatch. The COM bridge and MS Office applications seem to be the limiting factor.

I recommend to start with dynamic calls and maybe create bindings from idl files later. If you explain what went wrong using arsd.com maybe I or someone else can help.

Performance is my aim. In tight loops, late binding causes a significant delay. So I decided to use early binding, at least for MS Word. But yes, I can use a hybrid plan for other COM objects. I actually cannot remember the exact problem I faced with arsd.com. I was trying to use the COM object provided by QTTabBar (my file manager plugin), but ARSD couldn't connect to it. At that time, Adam suggested some tweaks, but they didn't work well. I think I can reproduce the issue, and I will let you know for sure. Thanks for your reply.