I am trying to handle COM events from a C# server to a C++ client. I am able to use the server regfree but my events no longer work.
Previously, with registration, the events were handled in the client via IDispEventImpl from the ATL.
I haven't been able to find any articles directly addressing this but I did see a suggestion that IConnectionPoint does not inherently require registration.
I also saw some suggestion that IDispEventSimpleImpl may work regfree.
IDispEventImpl requires access to a type library. You'll need to include a reference in your server manifest, so that it can be loaded into the activation context:
<file name="mydll.tlb">
<typelib
tlbid="{TLBID}"
version="1.0"
helpdir=""
flags="hasdiskimage"/>
</file>
Your client sink needs to be declared with the typelib ID as well:
class CMySink: public IDispEventImpl<1, CMySink, &IID_IEvent, &TLBID, 1, 0>
As an alternative, you can also implement IDispEventSimpleImpl, which works without a type library.
Related
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.
I'm registering components that require special handling on release (namely, a WCF clients) via a config file.
<autofac>
<components>
<component
type="SomeType"
service="ISomeType"/>
</components>
</autofac>
However, via the configuration file, I don't see how I can specify an event.
I've looked at implementing the OnRelease event via a module, but I seem to lack access to some of the innards required to get it working. Mainly, in:
registration.Activating += (s, e) =>
{
var ra = new ReleaseAction(() => ReleaseWcfClient(e.Instance));
e.Context.Resolve<ILifetimeScope>().Disposer.AddInstanceForDisposal(ra);
};
The ReleaseAction class is not available outside Autofac.
Autofac does not support setting up events via XML configuration. You must do that in code.
However, one way you can do this in a more cross-cutting fashion is to create an Autofac module and override the AttachToComponentRegistration method. In there, you can test each registration for something (like whether it's a registration for a particular interface) and attach your Activating event handler there.
There is an example of using AttachToComponentRegistration on the Autofac wiki showing how you can use this event to wire up log4net.
Two other notes:
You might be interested in using the UseWcfSafeRelease() registration extension for WCF client proxies. I don't know what your ReleaseWcfClient() method is doing internally, but if the point of it is to handle the possible exceptions from WCF, Autofac has that in UseWcfSafeRelease(). You can read about that on the wiki.
If a component implements IDisposable (the way WCF clients do) then Autofac will automatically track it and handle disposal. If you have something specific you want to run when Autofac executes disposal, you'd want to use OnRelease for the registration. If it implements IDisposable and you want to set up your own disposal solution, you need to register the component using ExternallyOwned() so your component isn't double-disposed.
(I don't know if either of those latter points apply here, but thought I'd raise them since we were in the territory.)
When I register my .NET Assembly with regasm.exe the registry key
HKEY_CLASSES_ROOT\CLSID{111E32AD-4BF8-495F-AB4D-6C61BD463EA4}\InprocServer32
is set to "mscoree.dll".
However, I am trying to mimic an existing COM-Server that was written in C. When registering this old COM-server the InprocServer32 is set to the full path to this component.
Unfortunately the existing system (a plugin host that I can not change) reads and use this value - an is confused by the "mscoree.dll" value.
My solution might be to patch this registry entry manually - but I would like to understand why regasm writes "mscoree.dll" into InprocServer32 .
The explanation is quite easy. When you use a native (unmanaged) COM server in-proc, it is loaded into the consumer process and the consumer process directly calls its functions.
This can't work that easily with a managed code COM-exposed assembly. In case of managed code an intermediate layer is needed that performs the managed/unmanaged interaction. mscoree.dll acts as this intermediate layer. So when the consumer calls CoCreateInstance() mscoree.dll is loaded and emulates the COM server by loading the COM-exposed assembly managed code and forwardind all calls to the latter.
i have two web services. One with user functionality, one with admin functionality.
Both services effectively work with the same object types, for instance:
AdminService provides functionality for deleting/modifying Customer objects
UserService provides functionality for listing/reading Customer objects
Now in the client i have two service references, Webservices.Admin and Webservices.User.
If i use the UserService to retrieve Customer objects, i cannot manipulate those via the AdminService, since the UserService retrieves objects of type Webservices.User.Customer, however the AdminService works with objects of type Webservices.Admin.Customer.
On the server side both types are identical, just belong to different namespaces in the client.
Now the question: How can i share types across different service references?
Check out https://github.com/geersch/WcfSvcMap
By tweaking the Reference.svcmap file you can make sure only one class is generated for each DataContract used by the different service references.
Note: Remember to delete the content of the node before pressing 'Update Service Reference'
If you're controlling both ends of the communication, and both ends are .NET only, you could do this:
put all your contracts, including your data contracts, into a separate "Contracts" assembly
reference that assembly in both the server side implementation code, as well as the client side code
If you do this, when adding the service references, WCF will find and use that shared assembly, and not create new types for the entitites. In your case, you'd only ever have one type Contracts.Customer or whatever you're dealing with.
This works only if you control both ends of the wire and have .NET on both ends! But in that case, it's a great way to share contracts - especially data contracts - across both the server and any number of clients.
Use the slsvcutil to create the WCF proxy on the clientside (assuming the clientside is a .net application), reference the DLL which contains your objects and it will be used for all endpoints that pass the same object in the DLL
Open Visual Studio Command prompt from the Start -> Visual Studio 2008 -> Tools -> Visual Command Prompt
goto directory similar to
C:\Program Files\Microsoft SDKs\Silverlight\v3.0\Tools
type slsvcutil and follow the syntax
slsvcutil http://somewcfservice:8080 /r:CommonLibrary.dll
where CommonLibrary.dll is the dll that contains the business objects
[edit] fixed the fact that the project is a silverlight project
There is an easy way to share types between client and service, just by adding reference to shared type assembly to your client BEFORE adding the service reference.
You can find the detailed scenario and sample project there:
http://blog.walteralmeida.com/2010/08/wcf-tips-and-tricks-share-types-between-server-and-client.html
We are adapting our client side relatively complicated application (ActiveX / .net / Delphi / C++ / COM ) to use SxS to achieve non admin deployment and isolation from older versions of our product.
We were able to achieve this goal for almost all our in proc components such as our .net ui, Delphi ui, and the COM servers we use in proc by composing a manifest file which described all the libraries used by our process, with no registration on the client of any of the components (almost).
And here comes the almost part:
At the moment, our application invokes (from it's c++ portion) an out of proc ActiveX server (Delphi ActiveX EXE), which in turn itself invokes another set of out of proc ActiveX servers (third party plugins, any thing goes here, Delphi, C++, any thing as long as it's out of proc ActiveX EXE and implements our interfaces).
As we know SxS does not support out of proc ActiveX servers. And we can't use these objects as in proc com servers in our main process because that would require a major rewrite of our application and even worst, a break of our public facing API which is used by third party tools and vendors, an api break which we can't allow.
We have stumbled on this article which describes how IHTMLDocument2 can be extracted from an Internet Explorer window running in a separate process. Which made us think of this approach:
We would create a secondary satellite application / process which will run the ActiveX as in process server.
Then we will use LresultFromObject and ObjectFromLresult to transfer a reference of the ActiveX object from the satellite application to the main application process. The satellite application will have it's own manifest file which will allow it to run in SxS mode.
Same approach will be taken to communicate between this Delphi ActiveX EXE and the third party AciveX EXE Plugins
There is an alternative solution, which for the moment we do not prefer over the proposed solution above which is to use .net remoting and .net com proxy classes to open the communication channel between the two processes, by translating the com request to .net remoting, and back to com on the second process.
So here comes the question:
What do you think about this approach ?
Do you see a better solution to the problem ?
It is possible to do. What is needed:
An application needs to start a server itself rather than relying on COM to do it. You don't need the extra indirection provided by the registry, just use CreateProcess().
A server should register its class factories in its main() method with CoRegisterClassObject().
Important: the CLSID it uses for each factory should be altered to be unique for each service instance. This ensures that the client connects to the correct server. I simply XOR the process ID with a class factory CLSID. The client knows the process ID as well so can make the same alteration.
The application should call CoCreateInstance() in a loop with a Sleep() call to wait for the object factory to appear. Don't declare failure until at least 60 seconds have passed (that bit me).
Both the application and the server need a manifest that contains a <file> element for each proxy/stub DLL and <comInterfaceExternProxyStub> elements for each interface that is remoted.
Alex,
nobugz is right, you can access the Running Object Table to create an instance of a COM Object from a currently running process of your Delphi automation exe.
However I have found a big issue that I cant explain. I can only access the object via the variant dispatch method when working this way.
Basically if my Active X exe is not registered, I get an "Interface Not Supported" error if I try to instance the object through interfaces for example:
WebUpdate : IAutomation;
WebUpdate := CoAutomation.Create; <-- Wont Work Error
WebUpdate : Variant;
WebUpdate := CreateOleObject('WebUpdate.Automation'); <-- Works Fine
If I register the active x exe using regserver the problem goes away!!
Go Figure!