Direct access to C++ ATL COM objects - c++

I have an ATL/COM implementation of an interface, which I need to instantiate in my main code and pass to another COM object. This implementation is in C++.
From my main C++ code, I would like to access directly to the object (not through the COM port), and access class members and methods directly.
I think that the way to go is to add DECLARE_NO_REGISTRY() in the ATL/COM class; then call myCOMClass:CreateObject() instead of CoCreateInstance; but I do not know how to use this (and did not find any example).
I tried several combinations with no success.
In my main code:
//I added this line to call the lib directly
#include "comClass\StdAfx.h"
#include "comClass\comClass_i.c"
#include "comClass\comClass.h"
//I removed this line to bypass COM
//#import "comClass\comClass.dll"
//What can I put here to replace this block, bypass COM
//and being able to access class members??
CoInitialize(NULL);
comClassInterface *myObject = NULL;
HRESULT hr = ::CoCreateInstance(__uuidof(comClass),
NULL,
CLSCTX_INPROC_SERVER,
__uuidof(comClassInterface),
(void**)&myObject);

More or less "standard" wat to create COM objects directly:
CComObject<comClass> *myObject;
CComObject<comClass>::CreateInstance(&myObject);
That's it basically.. You could also just do "new comClass" if the class is not abstract, which is normally the case when you use ATL.

Related

Why COM classes need constructor? How to use COM class without registration?

I am looking into DirectShow samples from Windows SDK. Many of the classes feature non-default constructor. How those constructors are called? Who supplies arguments?
Can I use those classes in C++ programs without registration? If so I could use class constructor directly.
If I use a COM class without registration what happens in the following code fragment:
Foo * foo = new Foo(.....); // note, not using CoCreateInstance
Bar * bar = foo->QueryInterface(...);
bar->Release();
delete foo; // CRASH?
Thank you!
It has nothing to do with COM, it is just the framework is built this way and constructor arguments in DirectShow BaseClasses are necessary to get everything together - the class, the ancestor, the instantiating factory.
Using COM class without registration might be or might not be possible. I suspect you might be interested in using DirectShow filter without registration instead, and there is a good article on the topic: Using Filters Without Registration.
A C++ class that's exposed as a real COM coclass cannot in general have a constructor that takes arguments. There's no mechanism for the COM client code to pass arguments to the CoCreateInstance() function. A COM interface typically has an Initialize() method to supply required initialization. Technically that can be doctored as well, CoCreateInstance is just a convenience function that hides the class factory (IClassFactory). A custom class factory with a custom CreateInstance() method is possible, but rarely done.
Microsoft uses the interface-based programming model that's common in COM code in non-COM code as well. DirectX is a good example. Think of Direct3DCreate9Ex() as the class factory.

Initial Object Reference for OLE Automation Object with constructor

I'm trying to interface a library that exports an Automation compatible interface via a .TLB.
The TLB lists functions inside the interfaces to retrieve object references; the .TLH includes these as nonstatic member functions, which makes it difficult for me to call them without an object reference; thus, I have a bit of a chicken-and-egg problem here.
What is the correct way to invoke functions from C++?
Use #import on the .tlb file, then use CreateInstance() method of an appropriate smart pointer type to instantiate the object, then just call member functions.
Something like this (error handling omitted):
#import ThatTlbFile.tlb
//at some point in your code you have to init COM
CoInitialize(0);
// once COM is initialized
IInterfaceOfInterestPtr object;
// this will ask COM to instantiate an object
object.CreateInstance( __uuidof( ComClassOfInterest ) );
object->CallMethod();

Inheriting from a COM class

I'm working in Visual Studio 2005 with a pure unmanaged project (C++). I have a COM class, from a third party, in a OCX file. This class is a control ("widget"). I've been using it through a IDispatch wrapper class generated using the Add Class from Typelib Wizard.
I would like to extend this class in a few ways and public inheritance would be way more practical than compositing (I want the derived object to expose every single method that the parent class does). The derived class should also be available as a COM component.
Can I do this? If positive, how can I accomplish this?
It is not possible to inherit from COM classes as you can in C++. There are workarounds though:
COM Aggregates
Forwarding
COM aggregates is only useful if you want to add an interface (with implementation) to an existing COM class. You cannot intercept calls to the aggregated object.
Forwarding means that if you have an interface IExistingInterface, you implement your own class that implements IExistingInterface. In your class you keep a reference to an instance of the object you want to "inherit" from. In your implementation of IExistingInterface, you forward calls as appropriate to the "inherited" object. This method gives you total control.
Example: (pseudo-code!)
class MyClass : IExistingInterface {
IExistingInterface* m_pInherited;
public:
MyClass() {
::CoCreateInstance(CLSID_OtherImplementation, ..., ..., IID_IExistingInterface, (void**)&m_pInherited);
}
// IExistingInterface methods
HRESULT MethodX() {
// Do some pre processing
HRESULT hr = m_pInherited->MethodX();
if(FAILED(hr))
return hr;
// Do some post processing
return S_OK;
}
};
Edit:
I really recommend that you use ATL to create your COM component. In that case, construct the "inherited" object in FinalConstruct() rather than the C++ constructor.
You can create a new interface that derives from the first. Your QueryInterface function will need to respond to both GUIDs and deliver the proper pointer. Once you've done that, have your concrete class implement the superset of the functions (i.e. all of the second interface, including everything inherited from the first.)
If your concrete class will also inherit from a concrete class in the library, you're going to have a diamond inheritance pattern. You can search for solutions to that, I'd start here: Diamond inheritance (C++)

How should I create classes in ATL project?

I'm writing an ATL project and I wonder how should I create classes here.
Right now I have one class created by Add/Class/ATL Simple Object. I want to divide it to smaller classes but method from this classes should use CComPtr and have CComPtr as an argument. I can't create 'simple' c++ class because I don't have CComPtr there.
Should I create ATL classes by ATL Simple Object Wizard and then use interface for this class to call methods. Like here:
CComPtr<ITestAtlClass> tptr;
tptr.CoCreateInstance(CLSID_TestAtlClass);
tptr->test();
And should I add all public methods by Class View/ITestAtlClass/Add/Add Method?
What about constructors? Do I must initialize my class only by properties (and add them by Class View/ITestAtlClass/Add/Add Property)? And pass every com object by IUnknown interface?
Can somebody tell me how it should be done in ATL project. I will use this smaller classes internally (nobody will create this classes outside my DLL) just to make my code more readable.
I don't understand your comment that you can't use CComPtr from a simple C++ class. Can you please clarify?
I see two strategies:
build a clean C++ object model that solves the problem, and then wrap it in a thin facade layer of one or more COM objects
Use ATL classes throughout, and use CComObject<> and derivatives to instantiate and maintain these without the overhead of CoCreateInstance and the limitations of only using public interfaces.
The first one is usually much nicer, but if you're building a data-heavy object model, the second can be a useful technique.
If you have an ATL COM class called CVehicle, that derives from CComObjectRootEx<> and friends, you can instantiate it like so;
CComObject<CVehicle>* vehicle = NULL;
CComObject<CVehicle>::CreateInstance(&vehicle);
vehicle->AddRef();
// To get at any of its interfaces, use:
CComPtr<ICar> car = 0;
vehicle->QueryInterface(&car);
// And to delete object, use:
vehicle->Release();
There's also variations on CComObject<>, e.g. CComObjectStack<> that use different allocation and reference counting strategies.
As you can see, this is pretty messy. If you can explain what you mean by your comment on not being able to use CComPtr, maybe I can expand on that.

C++ ATL Member Variable access help

I am not familiar with this, and can use a kick start.
I am using ATL (unmanaged C++) user control and would like to use the ShockWave ActiveX object. I need to know how to declare it so that I can set a property or call a method.
For instance, if I could assign a variable to it, then I would like to call 'variable->LoadMovie()'
I know this is super ridiculous... almost embarrassed to ask it here. ;) (almost)
If you #import the dll (which I recommend when working with COM because it makes your life SO much easier), you can use a smart pointer paired with the CLSID of the object. Remember that smart pointer classes have the post-fix 'Ptr' after the interface name.
For instance:
ISomeInterfacePtr pSomeInterface( CLSID_SomeComponent );
HRESULT hr = pSomeInterface->SomeMethod();
Hope that helps.
EDIT: If you want to check the HRESULT of the allocation, you can do the following:
ISomeInterfacePtr pSomeInterface = 0;
HRESULT hr = pSomeInterface.CreateInstance( CLSID_SomeComponent );
I cut&paste the necessary code so many times I can't remember the exact syntax but you have to:
get a CComPtr<> of the correct interface,
CreateInstance the object
QueryInterface to get the interface you want (assuming you're not using the CComPtr)
then call methods on it.
Alternatively you can #import the dll, then the compiler will generate a c++ class with all the methods and properties for you.