How can I create a COM object in Rust that inherits from a COM object defined in C++? - windows

I am trying to make a Rust program that emulates a webcam. This question and this answer suggest that the best way to do this is by creating a DirectShow source filter. Based on the PushSource sample in the Windows SDK and some C# implementations on CodeProject, it seems like the canonical way to do this is to extend the DirectShow BaseClasses provided in the Windows SDK. However, this is where my understanding breaks down.
I found the cxx crate and was able to get the classes from BaseClasses into my program, but how do I inherit from them or instantiate them? This crate does not seem to be designed for use with COM, and it is not clear how to call the constructors of classes.
Once I have done that first part, how do I expose my new classes as COM components? I found the com crate, but it seems to expect me to import the base classes using their GUIDs. However, I have no idea how to figure out what their GUIDs might be.

Related

COM Objects in Direct3D

As mentioned in Microsoft documentation there are two ways to create COM objects:
The module that implements the object might provide a function specifically designed to create instances of that object.
Alternatively, COM provides a generic creation function named CoCreateInstance.
In direct3D you can use first method to create Objects like you use D3D11CreateDevice()
but how you do this by the second method.maybe you need CLSID_D3D11CreateDevice which I didn't find.Is there any library to include or maybe it's impossible to create by the second way.
Also I really like to know if there is a way to see COM objects and what interfaces they implement.
DirectX APIs are not "true COM". These APIs derive from IUnknown for reference counting and polymorphic interfaces for versioning, but they do not follow all the other rules of COM objects. The lifetime rules are also modified for "child" objects, and DirectX APIs only support COINIT_MULTITHREADED.
This is a design pattern known informally as "COM lite" or "nano-COM".
Objects are created with a Win32 "flat" factory function
Objects generally support only IUnknown, the main interface, and derived versions of the main interface
Methods on interfaces can return void or HRESULT
Not all methods need to be thread-safe
They do not support COM aggregation
Interface pointers as parameters do not support client-provided implementations
Direct2D/DirectWrite and Windows Imaging Component (WIC) support CoCreateInstance as did did the original XAudio2 for Windows up to version 2.7 and legacy XACT. Otherwise, "DirectX" components do not support registry-based or manifest-based creation.
This pattern provides a stable "Application Binary Interface (ABI)" and maps well to C++ single-inheritance of pure-virtual classes. It provides an easy way to extend with new versions to add methods, and reference-counting for lifetime management. The resulting APIs are generally compatible with the IID_PPV_ARGS macro as well as COM smart-pointers like Microsoft::WRL::ComPtr, winrt::com_ptr, or the older ATL CComPtr.
See Microsoft Docs: Programming DirectX with COM
More recent versions of DirectX like DirectX 12 have adopted "strongly-typed bitmasks" which were not used in older versions. See this blog post.
While historically the DirectX "COM lite" APIs have provided C support through macros, the most recent guidance is to just support C++ and make use of C++11 features like strongly-typed enumerations (a.k.a. scoped enumerations). You'll see this reflected in the DXCore interfaces.

How does COM achieve language interop?

I understand how COM can achieve compiler agnostic C++ code, since it defines an ABI by being careful what features of the C++ language to use. It's just C++ code talking to C++ code in a really clever way. However I still don't understand how it can allow for language interop with C# or Javascript for example.
Where is the boundary? The only explanation I have right now is that the language compiler itself must have special support for COM so that it can generate the proper assembly code to allow for accurate communication between caller/callees.
Since you've tagged your question with WinRT, I assume you're asking specifically about how this is achieved by WinRT language projections. In that case, all languages must have some way to map their natural language constructs to the COM ABI that WinRT defines. That ABI is derived from metadata encoded in the ECMA 335 standard and special rules are applied to transform the abstract metadata into a concrete ABI. There are naturally different ways to achieve this. The CLR itself was updated to support WinRT in C#. The Visual C++ compiler was (sadly) updated with language extensions to support WinRT via C++/CX. The C++/WinRT approach is very different in that it requires only a standard C++ compiler and all of the knowledge about WinRT is delivered via a standard C++ header-only library. Other languages might take different approaches, but at the end of the day they must agree on the way that types expressed in metadata are transformed into objects and virtual function calls on the ABI based on COM.
And while this process is not well documented at the moment, C++/WinRT is one of the only open source language projections and thus acts as a useful reference implementation for those who need to understand how WinRT works under the hood.
https://github.com/microsoft/cppwinrt
The "Type Library" is what enables interop of COM components between different languages.
https://learn.microsoft.com/en-us/windows/desktop/midl/com-dcom-and-type-libraries
A type library (.tlb) is a binary file that stores information about a
COM or DCOM object's properties and methods in a form that is
accessible to other applications at runtime. Using a type library, an
application or browser can determine which interfaces an object
supports, and invoke an object's interface methods. This can occur
even if the object and client applications were written in different
programming languages. The COM/DCOM run-time environment can also use
a type library to provide automatic cross-apartment, cross-process,
and cross-machine marshaling for interfaces described in type
libraries.
The other approach for language interop (e.g. C++ projecting objects to Javascript) is that a COM object can implement IDispatch.
It’s not magic, of course.
COM sets up rules for language interop. It’s just a contract, with some helpful tooling. Each language that wants to support COM has to find a way to abide by the rules on its own. They all have to provide their own compatible mechanism one way or another.
In the case of C++, the rules appear to come for free as you mentioned, but be aware there is one caveat: the language standard does not specify the layout and mechanism of classes and virtual functions. The method mimicked by COM is one extremely common implementation of virtual calling (“the VTable”), and COM follows the exact layout used by the Microsoft compiler. But you can have a perfectly valid C++ compiler where classes with virtual functions would not be compatible with the COM layout. It’s just that nobody does that, at least not in Windows compilers. So even in C++ there is some “meeting in the middle” by the compiler.
In C, you have to do the whole thing by hand. Other languages might allow you to do the same thing (assembler of course).
To help compiled languages exchange information about specific contracts, COM provides Type Libraries and mechanisms to read them. A compiler or language that want to take advantage of them also has to “meet in the middle” and learn how to process them (for example, the Microsoft C++ #import directive; the VB6 Libraries menu).
No every language will support everything you can do in COM, because there is a point (in more obscure features) where the return on investment in implementing support in the language doesn’t pan out. Each language has to pick its own limitations. There is plenty of stuff that you can do in COM (read the IDL specs) that VB6 cannot do.
Because following COM rules in a script-like language is between inpractical and impossible, COM offers a higher-level approach (Automation) that is more amenable to dynamic languages, even if more limited. But a language implementer that wants to provide client support for Automation has to implement an understanding of the IDispatch interface, an activation mechanism, and a translation to its language’s proper facilities. And a scripting language wanting to provide support for creating COM servers has to work even harder to implement a valid COM IDispatch implementation and a standalone host engine on behalf of the user scripts. Even VBScript couldn’t do this at the beginning, until Microsoft added .SCR support with the Windows Scripting Host. “Meeting in the middle” again.
If a language wants to support both pure COM and Automation, they need to work double hard; support for one does not automatically give you support for the other.
For .NET languages like C#, most of the work is done for both native COM and Automation inside of the .NET Runtime, which provides the implementation of the COM Callable Wrappers (CCW) and Runtime Callable Wrappers (RCW) necessary to interact with COM, and handling the conflicts between the Reference Count approach of COM and the GC approach of .NET. Microsoft did all the work in one place so individual .NET language designers didn’t have to.
So, yes, the language implementer has to work extra to give the language special support for COM: following the binary layout rules, implementing a translation layer when needed, and/or possibly providing tooling to read Type Libraries.
Language Interop requires both sides (the caller and the callee) to “meet in the middle” somewhere. COM is just a specification that gives designers that middle ground, “a place where all can meet”.

Programming language for OSX components

I am going to develop an AudioUnit software synth component for use in Logic Pro, GarageBand, etc.
In Apple's tutorial, they use C++. Is this mandatory, or could I use Objective C as well?
I think you cannot avoid C++ completely. According to the documentation, you can create a new AudioUnit by subclassing Core Audio SDK’s C++ superclasses. This is, I think, mandatory.
However, you are free to mix C++ and Objective-C, so you should be able to create the C++ subclass and full-fill the requirements of an AudioUnit interface, but implement (most) of the functionality in Objective C.
Yet, the central part of audio functionality (the low level rendering callback) consists of procedures, which are mostly written plain C, as you may see in much of the sample code and open source examples. For me it worked best to write this part as stand-alone first, only upon making sure it does its job as desired -robustly and properly, to take care of defining classes, instances, methods and code reusability.

How I can enumerate the COM Object Members like interfaces, properties and methods?

Which WinAPI method or interface I can use to enumerate the interfaces, properties, methods(and parameters) of a COM Object programmatically?
You need to be more specific. There are two ways to interpret your question.
One is that you have a COM component (e.g. some library), and you want to programmatically enumerate interfaces/properties/methods of that. Usually (but not always), COM components come with a type library that contains full metainformation about all this - it's either embedded into the COM .exe or .dll, or is a separate .tlb file. In any case, if the COM component is properly registered in the system (e.g. using regsvr32), then COM provides a standard API to retrieve that type information, centered around ITypeLib and ITypeInfo interfaces.
Another interpretation is that you get a reference to a particular COM object, and you need to enumerate all methods/properties on that and/or invoke them by computed name, like Java or C# reflection, or Delphi RTTI. If so, then it is only possible if the COM object implements IDispatch interface, which allows you to do all of the above.
Well, COM objects are referenced through interfaces, which are opaque abstractions by design. You can't get at the underlying object without some black magic that will only work if you have a really good knowledge of the low-level details of the Delphi object model and the object was actually written in Delphi.
About the best you can do is examine the interface declaration itself, which will give you all the available information in its methods and properties.
I assume you want a list of all interfaces that will successfully QueryInterface. The answer is there's no intrinsic way in COM to do this. Some interfaces themselves provide this functionality like IServiceProvider.
You can get at everything you want from the registry, however this will take some time as the information is not ordered in such a way to give you the information you want without first analyzing most of it. If you download the utility OLEVIEW32 from the Microsoft platform SDK (available on MSDN) you can use it to explore the COM interfaces registered on the machine.
The fundamentals of COM work through the interfaces registered in the registry, under the HKEY CLASSES ROOT\CLSID. When you ask for a specific com object, it resolves to one of these guids, which in turn looks at the InprocServer32 section under this guid to determine what DLL/EXE to load, and what threading model to use. You could use this information to build a map of guids which also resolve to the same DLL (this is to get the classes)
In HKEY CLASSES ROOT\Interface is a link to all of the interfaces registered in the system. Again, its time to play lookup since much of this information is just pointers to another key, or type library. What IS here however and is useful is a list of GUID -> InterfaceName (default property of each guid).
In HKEY CLASSES ROOT\TypeLib is a link to all of the type libraries registered in the system.

Communicating with ActiveX with a GCC compiler

How do I reference and communciate with an ActiveX library from within my gcc compiled application?
Well, I've never actually tried it, but there is no reason you wouldn't be able to do this. You basically just need to have the interface definitions for the classes you need (might be able to get this from VS) and then make the appropriate calls.
The function CoCreateInstance is in Ole32.dll, so you could probably load the library, get the entrypoint, and then you just have to find the CLSIDs for creating the COM object you want, etc. As long as you are careful about only casting with QueryInterface, you should be just fine; COM was designed specifically to provide binary compatibility so that this would be possible.
http://msdn.microsoft.com/en-us/library/ms686615%28VS.85%29.aspx
the hardest part will be getting all the headers and such that you need.

Resources