How to load COM dll modules and expose their interfaces as out of proccess servers - com

I have an out of process server based on the ATL Service VC++2010 Template. Now I wont to extend his COM Interface by dynamically loading additional dlls that contain its own COM Classes.
The dll to load is based on ATL dll VC++2010 Template, containing a simple ATL-object "IMModule". I changed the corresponding .rgs file to connect the class from the dll to the EXE server by adding a LocalServer section and the server's AppID as follows:
HKCR
{
NoRemove CLSID
{
ForceRemove {59276614-A811-4D27-B131-514656E643D3} = s 'IMModule Class'
{
ForceRemove Programmable
LocalServer32 = s 'path to the service exe'
{
val ServerExecutable = s 'path to the service exe'
}
TypeLib = s '{250685C7-CBD3-4FF8-A3A6-2AF668794CFC}'
Version = s '1.0'
val AppID = s '{7EFD508A-53C6-4EA0-B21A-D29277B86CBC}'
}
}
}
In a dll init() method called by the service after loading the dll I call CoRegisterClassObject to register the IMModule class object. But im not sure how to obtain the IUnknown interface pointer (second parameter to CoRegisterClassObject ). I tried the following:
CIMModule::_ClassFactoryCreatorClass* pClassFak =
new CIMModule::_ClassFactoryCreatorClass;
IUnknown* pUnk;
HRESULT hr =
pClassFak->CreateInstance(CIMModule::_ClassFactoryCreatorClass::CreateInstance,
IID_IIMModule, (LPVOID*)&pUnk);
But the call to CreateInstance fails with E_NOINTERFACE.
So, how to register my IMModule class implemented inside a dll to be available for COM clients from my out of process server?

With the help from Roman.R I get the behavior that I need. I can't say thank you enough, #roman-r. I will precisely describe what I did, so maybe someone can retrace the steps and give me some response.
First I created an ATL based Windows service (named UmbrellaService). Inside UmbrellaService I added a simple ATL-Object named Control and added the method:
FindMeAnInterface(BSTR moduleName, IDispatch** ppDispach);
Thats all with the VC++ Wizard. Then I fixed the Control.rgs file by adding:
val AppID = s '%APPID%'
Why has VC++ still such bugs after 17 years of evolution? (See
CoCreateInstance does not start or connect to ATL COM service)
Then I created an ATL-dll Project, named MyModule, with a "Module"
simple ATL-Object inside. The Module class has a method
testMethod (LONG a, LONG b, LONG* sum)"
The MyModule dll is registered as a in-proc server. Furthermore the dll has some classes
that makes the dll a plugin as I need it.
In the PreMessageLoop method of the UmbrellaService the MyModule dll will be loaded with LoadLibrary and through GetProcAddress the address of a factory creation method is obtained. The factory creation method returns a plugin-dependent FactoryClass that acts as a plugin entry point. This is my COM-independent plugin mechanism.
Now to export the module interface from the plugin dll through the UmbrellaService interface I did the following: On the FactoryClass I add the method:
IDispatch* getInterface();
In getInterface method I call
CoCreateInstance(__uuidof(Module), NULL , CLSCTX_INPROC_SERVER , __uuidof(IDispatch), (VOID**) &pDispatch);
and return the obtained IDispatch interface. The FactoryClass::getInterface method is called inside the Control::FindMeAnInterface method of the UmbrellaService after comparing the name passed to FindMeAnInterface with the name provided by the FactoryClass. FindMeAnInterface returns the then obtained IDispatch pointer to the client.
On the client side I import the tlb file from the UmbrellaService and the tlb from the apropriate plugin dll. I call testMethod as follows:
IControlPtr pControl(__uuidof(Control));
_bstr_t moduleName("Module");
IDispatchPtr moduleDisp = pControl->FindMeAnInterface(moduleName);
IModulePtr pModule(moduleDisp );
LONG res = pModule->testMethod(42,23);
This all works indeed, but I am not sure if this is the way to do it. Did I miss something about reference counting? Will the plugin DLL be loaded two times? First time through my plugin mechanism and second time through CoCreateInstance? Something else I should note?
Thanks for your help!

I could not find my code so far. But I did check one of my favorite websites, The Code Project. It used to be popular especially with older technologies like COM (yes, it is). I hope you're already convinced that you have to use COM instead of new WFC or another technology.
Please check good documentation and sample code # ATL COM EXE doc. I believe I used this web page as a start of my past project.
Good luck and have fun.

Related

Using a Service Reference in VB.NET

i have added a service ref in my VB.NET application.
i can see the objects in the object browser. i need to log in first to obtain a session ID.
when I try
dim client as new serviceReference1.IGPSBulkData
I get an error
'New cannot be used on an interface'.
IGPSBulkdata is the only option that includes the login function so Im not sure how to make this call
any ideas?
When you add a service reference several classes are being generated from the service' WSDL. Take a closer look at the generated code 🤓 There will be something like GPSBulkDataClient.
This generated client class can be used to communicate with the service.
The error is correct; you cannot instantiate an Interface.
If you open Object Browser in Visual Studio and search for IGPSBulkData you should be presented with a list of classes which implement it. From there you can instantiate your client object (if that's what you need to do with that class).
So if there was a class called GPSBulkDataThing which implements IGPSBulkData your code might resemble:
Dim client as serviceReference1.IGPSBulkData = new GPSBulkDataThing(maybe with some arguments here)

Use of DllRegisterServer

DllRegisterServer is called, when Windows or OLE wants me to register my classes under HKEY_CLASSES_ROOT\CLSID. But I don't understand why this function has to be implemented, because when Windows/OLE can make calls to my DLL, then my classes are already registered with their CLSIDs and their path to the correct DLL. Can somebody tell me, what I am misunderstanding?
You are confounding the chicken and the egg. In order for COM to help a client app to create objects and marshal calls, it needs to know where your COM server is located. The client app just uses a number, a GUID, to tell COM what object it needs. The mapping from a GUID to code in an executable file requires COM to know where that file is located first. And, if necessary, how to marshal a call on an interface from one apartment to another.
It is registering the server that provides COM with that knowledge. It writes keys in the registry that COM uses to find the file back. Like the CLSID key, its InProcServer32 sub-key provides the path to the file. Etcetera. Or the manifest embedded in the client app if it chooses to use reg-free COM.
Observing this with SysInternals' Process Monitor can provide a lot of insight. You'll see what DllRegisterServer() does and how a client app uses those keys.
For the peoples wondering about Title of Question
Example of COM object is Dynamic Context Menu ( which would be a DLL)
to register it-
First Make a Random GUID under HKEY_CLASSES_ROOT
Under That GUID make key named "InProcServer32"
set value of this key as full path of your DLL
This is called Manual Registration
people's with no knowledge of registry editing should also be able to register your dll too.
for that, you should write codes to make these GUIDS and InprocServer32 keys etc programatically Under the DLLRegisterServer() Function in your DLL
so that , people with no knoledge of registry editing will be able to type -
regsvr32.exe "full path of your DLL"
in command prompt for registring your DLL
when they type that command, regsvr32.exe will do nothing but call that DLLRegisterServer() in your DLL
and by calling this function, codes of writing registry keys such as making random GUID and InprocServer32 keys will be Executed ( which you have written )
so registry entries will be made and that is called Registration.
so , according to me regsvr32.exe was just created for the people who have less knowledge of how to edit registry.

Changes in registry keys after adding a new interface and a componet to out-of-proc COM server

I am going through a code that has a exe having a COM server(a COM class implemented in ATL).
It has a .idl file having all interfaces defined.
Now after registration of the COM server, i went through the registry entries and i could find the following.
Each interface has a entry with its IID and having ProxyStubClsid32.
There is one interface which is implemented by the COM server that i mentioned, which has IID in key field = the value of ProxyStubClsid32 and every other interface interface entry is having this same IID entry in its ProxyStubClsid32 field.
Why this is so ??
Next when i try to add a new interface and new COM component implementing this interface to the exe, and do its registration what i could observe in registry was that now IID entry for this new interface and its ProxyStubClsid32 are same.
And the newly added IID is present in ProxyStubClsid32 of all other interfaces now.
What gets into ProxyStubClsid32, how is this decided?
I want the previous IID to be present in ProxyStubClsid32 even after adding my new interface. How can i do this ??
Also does explorer.exe caches this registry entry as i am implementing a shell extension which loads the component, i think it is referring to old entries so querying the new interface on that exe doesnt work. Once i restart explorer.exe everything works fine.
Could anyone also comment on this.
Answer to this seems has some hints to my problem : Registry keys for out-of-process COM server
Thanks in advance.
What is in ProxyStubClsid32 is actually the interface used for marshalling by the MIDL. It is used because your interfaces inherit from IDispatch and is needed so the compiler takes care of marshalling (as its an OOP server, you NEED marshalling).
For our team we had some problems registering the server in some of the machines (/RegServer was not enough), but using a small exe with this code fixed all registration issues (and thus the E_NOINTERFACE problem that you may have), just call it after every build or on installation:
// Register the server
String^ l_TLB = l_Path + "\\MyServer.tlb";
IntPtr l_TLBP = System::Runtime::InteropServices::Marshal::StringToBSTR(l_TLB);
ITypeLib *pTypeLib;
HRESULT hr;
hr = LoadTypeLibEx(static_cast<LPCOLESTR>(l_TLBP.ToPointer()), REGKIND_REGISTER, &pTypeLib);
if(SUCCEEDED(hr))
pTypeLib->Release();

Reference Windows Form Project From another Windows Form Project in same Solution

I have a solution with several projects most of which are code or control libraries. I have a main windows forms application that references and uses these libraries. What i am trying to do is create a 2nd windows application that extends the main one, but i would like to be able to deploy them as separate exe's.
When i try to add a reference to the new app referencing the main app; all seems fine until i try to run the new app i get several error msgs similar to below:
Error 1 Could not find file 'ADODB.dll' referenced by assembly 'D:\Visual Studio 2005\Projects\X\XX\bin\Debug\XXX.exe.manifest'. <newAppName>
i have tried adding references to all the dll's in the error messages and they are still listed when i try to run the new app. I thought of a few work arounds but they require user changes to maintain separate exe's at deployment. I would like to avoid this if possible. Any ideas?
Thanks in advance, Jeff
Your windows forms applications should not be the point that you extend, the exe files should really just be a shell for launching your process (as much as possible anyways). So this response doesn't answer your specific problem of reference exes as this is not considered good practice.
All the extensions should be made to your code or control libraries off a known interface or contract. Generally the process for extending applications like this is to use alternate or additional DLLs which are loaded at runtime.
Say you have an application called clock which is to display the time.
You can structure your application with a set of contracts (or interfaces) in a referenceable DLL "Clock.Contracts.dll":
public interface ITimeService
{
public string Name { get; }
public Date GetTime();
}
You then have each implementation of this in another DLL ("Clock.LocalComputer.dll", "Clock.InternetTime.dll"
public class LocalTime : ITimeService
{
public string Name
{ get { return "Local Time"; }}
public Date GetTime()
{ return Date.Now; }
}
In the UI/EXE you always reference the interface don't call the implementation.
How do you get an instance of the implementing class, using Reflection to identify if a class in a DLL implements the interface and Activator.CreateInstance to generate the class.
http://gsraj.tripod.com/dotnet/reflection.html
There are patterns like Inversion of Control and Dependency Injection which help to address these things in a standardized way in your application. 3rd party libraries like Castle Windsor, Spring can assist. A google search on these will give you some reading material.
I will say that it can take a while to fully get your head around these things.
ok i found a reasonable work around. Basically you add all the reused forms as existing items, but instead of just clicking add you click the drop down arrow and choose add as link.
It would be great to redesign as JTew suggested above but this gets me where i need to be without having to move code.
You can find more information here
Thanks for all your time looking this over and hopefully is helpful to more
Jeff Spo

Error when writing C++ wrapper for WCF

I'm getting the following error in my WCF project:
"An unhandled exception of type 'System.InvalidOperationException' occurred in System.ServiceModel.dll
Additional information: Could not find default endpoint element that references contract 'IPhiFeed' in the ServiceModel client configuration section. This might be because no configuration file was found for your application, or because no endpoint element matching this contract could be found in the client element."
The WCF project is a bit experimental: is a mixture of managed and unmanaged C++, and C#. I've got everything working in pure C#, but I have to consume WCF from unmanaged C++, thus the need to write a C++ wrapper around WCF.
Update
As requested, here is the code thats throws the exception:
// WCF library written in C#
public class EngineAPI : IEngineAPI
{
public FeedClient client;
// constructor
public EngineAPI()
{
// the line below in this C# library works *perfectly* when called from a C#
// console app, but it fails when a C++ console app calls the same C# library
// UPDATE: exception fixed if you copy app.config to out.exe.config, see comments below
client = new FeedClient(); // << exception here
}
.....
}
// NOTE: the line "client = new FeedClient" instantiates generatedProxy.cs,
// which is generated with svcutil
// NOTE: if I temporarily delete "app.config" from the pure C# project, it generates *exactly* the same error as I'm getting when I attempt to call everything from the separate C++ project with managed code.
Update
Found the problem, it was unrelated to the code: you have to copy app.config to out.exe.config. I now have a 100% working C++/CLI project calling a C# library which uses WCF. See my comments below.
Typically when you are using wcf in the client project you have entries in your config file that describe the binding to be used as well as the endpoint where the service is located:
I am presuming that your FeedClient class is the class that inherits from ClientBase(IPhiFeed). ClientBase actually defines numerous constructors, if you call the constructor with no parameters it will attempt to find the 'default' client endpoint in your configuration file; and in this case there isn't one because the only endpoint defined in the configuration has a name. To correct this you can do one of two things: you could call the ClientBase constructor that takes a string parameter with the endpoint name: ClientBase<IPhiFeed>("MyService")
or you could change the configuration file so that the endpoint does not have a name:
Edits:
The code you have in your question looks like C# code. Does the FeedClient class inherit from ClientBase? If yes and the C# code that calls it works then what is the C++ code that doesn't work? In general in C++ code you can have both managed and unmanaged code; that is unmanaged code can call into managed code. In your unmanaged project you should do the following: go to the property page for the project, Click Configuration Properties the General; in the general tab under Project Defaults the second from the bottom option should be Common Language Runtime Support, make sure it is set to Common Language Runtime Support (/clr). Add the project that contains the FeedClient class in as a reference to the unmanaged project if necessary. Then you should be able to instantiate the FeedClient class directly in unmanaged code:
MyNamespace::FeedClient wcfClient;
wcfClient.SomeMethod() // Add parameters as appropriate...