Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

COM is an ABI standard. The structs are defined in terms of C with Winapi (stdcall) calling convention. Very little needs reverse engineering - it's all pIntf->vTable->func(pIntf, ...). You can explain it on a whiteboard in a couple of minutes.

The way MSVC does it may need reverse engineering (it may be patented btw). I could explain how Delphi implements COM interfaces, but any specific implementation is actually more complicated than the ABI, because they're trying to add implementation ergonomics on top of the basic calling convention.



Is the ABI documented anywhere? Every time I google around for it, I just get information like "COM is ABI stable and language agnostic" but not what the ABI is. I've successfully implemented implementations of single COM interfaces and get the basics, my trouble was in implementing many interfaces for the same implementation and running into copious segfaults when testing the Rust implementation through a reference app written in C++.


Here are some good COM books.

Essential COM by Don Box

https://www.amazon.com/Essential-COM-Don-Box/dp/0201634465

Inside COM by Dale Rogerson

https://www.amazon.com/Inside-Microsoft-Programming-Dale-Rog...

Then if you have access to public libraries, maybe one of them has one of the several Microsoft Systems Journals issues, later MSDN Magazine, with plenty of low level COM articles.

COM is from the days where good documentation was to be found in books, not on the Interwebs.


+1 for Essential COM by Don Box, it still survives my bookshelf purges..."just-in-case". IUnknown and IDispatch are burned permanently in my memory from a period of my life building a COM/CORBA bridge.


I'm gonna piggyback on your comment to give another shout out to Essential COM. I haven't touched COM in ages but that book is so good I still pick it up every once in a while -- and it was a lifesaver back when I did touch COM on a daily basis.


Wow, that's a throw back to the late 90s, early 2000s. I'm still slightly scarred from working with ATL and COM. A lot of people around here would probably be surprised to hear that there were even Python -> COM bindings back in the day that were even used to ship server software once upon a time. Anyway, I remember that Don Box book well.


Not only "back in the day" – those COM bindings for Python were most recently updated last month: https://pypi.org/project/pywin32/#history

I highly recommend using them if you're ever forced to work with VBA and need to implement some non-trivial functionality.


There are also new Python bindings for WinRT (which is based on COM): https://github.com/Microsoft/xlang/tree/master/src/package/p...


IronPython supports .NET Core which supports COM


Yea...Python and Powershell are the only languages that I know of outside C#/VBA/VB.NET with decent COM support. I hate COM, but it works.


Delphi, Eiffel as well.


True... I've looked at Delphi, but at this point I doubt the license fee is worth it compared to say C#. I've never known anyone who actually used Eiffel though.


oh how i wish i knew this back when...or just looked harder i guess ;)


thank you!



What's to document? The stdcall / WINAPI calling convention, which is of course OS and architecture dependent, but can be summarized as on the stack, right-to-left, callee pops.

The rest is just that interfaces are doubly indirected to get to a vtable (an array or struct of function pointers), the method is chosen by ordinal in the vtable (first three are always the IUnknown methods), and the interface is passed as the first argument.

How you construct those vtables and how you select one to return in QueryInterface, and how you implement interfaces (i.e. traits) so you can convert them into a vtable is where all the work is. You can do anything you like that works as long as it's called according to the COM conventions.

Delphi works by implementing each method in the vtable with a stub which subtracts the offset of the vtable pointer in the instance data from the passed in interface, and then jumps to the implementation method on the instance after the instance has now been adjusted. Instances look like this:

    [class pointer, the native vtable] <- normal instance pointers
    [vtable interface 1] <- COM interface pointers
    ...
    [vtable interface n] <- COM interface pointers
    instance field 1
    ...
    instance field n
So you can see that in order to convert a COM interface pointer into an instance pointer that the methods expect, the COM interface pointer needs to be adjusted depending on the offset of the vtable in the instance.

In a language with multiple inheritance like C++, the compiler vendor targeting Windows may choose a layout which is suitable for COM's calling convention (there's more than one way to do MI, e.g. fat pointers is another way to go that wouldn't be COM-compatible). If the vendor does that, then they make implementation of COM interfaces much easier. And if they don't, well, life isn't going to be easy. Technically you could do a bunch of stuff with reflection and code generation, but that's harder and harder these days with security restrictions around code writing code. You could write macros which create statically initialized structures of the right shape, and fields of the right type, to emulate the same effect as Delphi's scheme as I sketched above, or some other method which would work with COM's calling convention.


Possibly relevant: Wine (Win32 implementation on Linux) has an IDL compiler, which compiles IDL (language for defining COM objects) into C: https://www.systutorials.com/docs/linux/man/1-widl/


Realize that COM is supposed to be used with code generators. You can write it in raw C even, but it quickly becomes intractable. Perhaps I did not read completely but this is something I see missing from the post -- the annotations fit what the pre-pass C++ code looks like, but don't mention that layer?


You may want to look at XPCOM. At one point it interoperated with MS COM, and it might still.


> The structs are defined in terms of C with Winapi (stdcall) calling convention.

This isn't quite right. The calling convention is a Windows C++ variant of stdcall. See this issue: https://github.com/rust-lang/rfcs/issues/1342

However, 99% of the time the difference won't be an issue.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: