Getting a pointer to an existing COM object? - c++

How do you get a pointer to an existing COM object that has been created on the same machine, in a different process?
I have a Credential Provider which creates an object that inherits ICredentialProvider. ICredentialProvider has a method SetSerialization.
I also have a service, from which I need to call the SetSerialization method of the Credential Provider. The thing is, I'm experienced in C++, but I'm a beginner with COM, so I don't know how. Microsoft's sample 'CSampleProvider's comments say to call the SetSerialization method from a 'remote client', but don't explain how - I assume they assume you know COM.
I've been reading MSDN and various tutorials about COM all day, and I've got to a point where I can create an instance of my Credential Provider in the service, but I need to get a pointer to the Credential Provider object that already exists, not create a new one, and I can't find out how.
How is it done?
Thanks.

The canonical method is via the Running Object Table. That assumes the object has a "moniker", i.e. a COM name, and that this moniker is registered.
Note that the ROT is a form of IPC, specifically a systemwide directory of COM objects.

As Raymond said, in short, you can't - not by any built in COM functionality at least. If you must, it will need to be passed via some form of Inter Process Communication.

Related

Can I have a COM interface in a service to be called from Windows Script Host?

My goal is to create a COM interface in my Windows local service, written with C++/MFC, whose methods could be called from a Windows Script Host JScript code running under a logged in interactive user account.
For instance, if I have a test.js that can be started with credentials of a logged in user, that does the following:
var Obj = new ActiveXObject("myservice.somename");
var Result = Obj.MyMethod("some data");
and then have MyMethod function processed in my service & return a value.
I know it's a general concept. At this stage I'm curious if such is possible (from a Windows security stand-point, i.e. calling system service from a user process) and if so, if there's any sample code that I can use as a basis for this?
I'm assuming that it must be some COM interface, right? But usually those go into a DLL. I've never tried to put them in a service.
Thank you!
I'm posting it for my own future reference, in despite of the treatment I got in the comments to my original post. It would've saved me a day of search if someone pointed me to this article...
This CodeGuru article, "COM in plain C, Part 2" explains how to create a COM interface that can be called from the Windows Script Host. His IExample2 project shows how to create an in-proc DLL that hosts the COM interface that can be called from a VBScript included in the same project. Then regiexample2 and unregiexample2 projects also show how to register/unregister the COM interface. The VBScript can be easily adjusted to work with JScript in my OP.
One word of caution though, that project is intended to be used for installation on a 32-bit OS. For 64-bit OS, you will need to build and register a 64-bit version of the in-proc COM Dll. The registration part from a 32-bit process is similar to the one shown, except that one needs to include the KEY_WOW64_64KEY flag when opening/creating registry keys.

Reusing the web browser control

I have a pure Win32 application (no MFC, etc.) to which I want to add a web browser control in a window. I know the basics of COM and can create a COM object for the browser using
hr = CoCreateInstance(
CLSID_WebBrowser,
NULL,
CLSCTX_INPROC,
IID_IWebBrowser2,
(void**) &pWebBrowser);
However, apparently one needs to call SetClientSite, passing an IOleClientSite*. How do I obtain such an interface? This example implements its own browser class, which provides the interface by deriving from it and implementing it (here). I tried to go along that path, but in order to instantiate the browser class, I would have to register it (no?). This seems awfully complicated - I just want to use an existing COM object, not implement and register my own. What am I missing?
Assuming I do implement my own ClientSite class as part of my application, is it possible to not register it, and just instantiate it by calling new ClientSite (and then fetch the interface as using QueryInterface)? Will this work, or is it mandatory to call CoCreateInstance?
There is an example on CodeGuru and another on CodeProject which contains the simplest implementation for hosting a web browser control implemented in pure C. You do have to implement your own IOleClientSite, but it is one of the easier classes to implement. Yes, it is mandatory to call CoCreateInstance or OleCreate to create the instance of the web browser control.
http://www.codeguru.com/cpp/i-n/ieprogram/article.php/c4379/Display-a-Web-Page-in-a-Plain-C-Win32-Application.htm
http://www.codeproject.com/Articles/3365/Embed-an-HTML-control-in-your-own-window-using-pla
Try WTL (header only library from MS). Install its project templates. Create a new WTL project from template and select "web browser" control option (or whatever is the name). Now you can investigate generated sources or (my personal recommendation) move your stuff into this project
I'm not sure what exactly you're trying to do ...
... but I'd start by trying to use a simple ShellExecute(), if at all possible:
http://msdn.microsoft.com/en-us/library/windows/desktop/bb762153%28v=vs.85%29.aspx
http://support.microsoft.com/kb/224816

Register a Dll in LOCAL_MACHINE

I want to register my Dll to specific path in registry and not in default path that it takes usually.. I am new to Windows and doesnt know much about it. Can any one tell me what all things i need to mention in my code piece or is there anything that can be added to it so that my dll get registers in HKEY_LOCAL_MACHINE.
Why would you want to do that? COM dlls must be registered at HKEY_CLASSES_ROOT, anything else makes no sense.
The reason is that when some other component needs to instantiate your COM server, they will typically call CoCreateInstance API which will lookup the class info in the HKCR hive of the registry and not somewhere else. If you would register your class somewhere else no other component would be able to find it which would be the same as if it was not registered at all.
You need to use Win32 API Registry functions:
Create (open if exists) key with RegCreateKeyEx
Set value with RegSetValueEx
Close registry key with RegCloseKey
See also some sample code.
You need to clarify what you mean by "register".
COM is a specification, and if you want to register your component for COM, you need to follow the spec. That means HKEY_LOCAL_MACHINE\SOFTWARE\Classes. It doesn't make sense to register a COM server anywhere else, because nothing will find it.
If you mean something else by "register" then please clarify.

Problems getting access to a STA object from another process

I have been trying something which may turn to be impossible in the end. It's been a long while since I've been in COM land.
Consider two apps and a COM STA DLL. First app loads COM STA DLL as a plugin and this DLL tries to register itself "globally" so that the second app sees it. Something like GetObject("Excel.Application").
I have tried two approaches (which may turn to be the same thing).
Approach 1: I have tried using CoRegisterClassObject to register my STA instance of an object. This call succeeds with S_OK. But if I try to GetActiveObject using the same CLSID immediately after CoRegisterClassObject, I get MK_E_UNAVAILABLE - 0x800401e3.
Is GetActiveObject the wrong API to call? If not, why would it fail?
Approach 2: I have also tried using GetRunningObjectTable, IRunningObjectTable:Register and CreateClassMoniker but when trying to get to the object from ROT in a second app, I am faced with another failure.
My STA DLL is properly registered and uses typelib for marshaling (which is also registered).
Am I missing something or is what I am trying to do not possible at all? If latter, are there any simple alternatives for me?
It seems when you want to use GetActiveObject your friends are RegisterActiveObject and RevokeActiveObject. I was totally off. It works perfectly now! I hope this helps someone.

Hold COM-reference in .net web service

I have tried to make a webservice interface to a state-holding COM component.
The webservice basically contains operations Start, Shutdown and GetCurrentState.
Start creates a COM component, Stop releases.
And GetCurrentState retrieves information from the COM component.
It seemed an easy thing, but after a day it still refuses to work.
I have tried storing the COM-reference as a member variable in the C# object. The object is constantly re-created.
Then I tried to store the COM-reference in the Session object. But still, something is still wrong.
Anyone know how one should store COM reference which should stay alive inside webservices?
/L
Assuming you are using ASMX here, and not WCF where you could control the life time little bit differently, each time a request comes in the class that services the request is recreated. This is the standard behaviour for ASMX.
What you need to do is store the COM object either inside the Cache[] or Application[] collections. It may still get destroyed when the worker pool is recycled. Some code like this is what you need:
public FooClass GetFooClassInstance()
{
FooClass instance = (FooClass)this.Context.Application["FooClassInstance"];
if (instance == null)
{
instance = new FooClass(); // Creates the RCW.
this.Context.Application["FooClassInstance"] = instance;
}
return instance;
}
The FooClass is the runtime callable wrapper for your COM object. The Application object contents is retained between requests. One thing you do need to watch out for is the threading model that the COM component is using as some can cause performance problems because they marshal calls onto a single thread.
Web service by its nature is stateless. Try creating Windows service and using Web service to control it. Start method would start Windows service and that service would instantiate COM-component. GetCurrentState method would communicate with the service and grab COM reference.
Another approach is to make your COM component COM+ accessible:
Open Administrative Tools -> Component Services.
Open COM+ Applications node.
Create new application. Select "Create an empty application" in the first wizard step. Type application name and select "Server application" option in the next step.
Create new component. Select "Install new component(s)" in the wizard. Locate and select your COM dll.
Go to component properties and enable object pooling. Set minimum and maximum pool size to 1. This will make your component a singleton.