I am writing a browser for com,that can retrieve the CLSID associated with the interface.
To do this,he need to know manything.For example.
Quote
invoke CoInitializeEx,NULL,COINIT_APARTMENTTHREADED
He must also know if the connection can be made by cocreateinstance or by progid.
Most of the needed informations are in the registry.
Some caller need a proxy before calling an interface (Idon't know how to make a proxy)
and more ...and more
---------------------------------------------------------------------------------------------------
What i search his informations,code,that help making connections.
Thanks for answer.
Most of this information is available in through ITypeLib for a specific class, however you might want to read this...
http://www.codeguru.com/cpp/com-tech/activex/apts/print.php/c5529
A proxy is simply a class that you can call members of another interface through without having to instantiate that interface directly. For example you create a class that uses an instance of IPersistFile, that class can be a Proxy for IPersistFile since you can call its methods through your class, your class would usually just have stubs for the target interfaces methods. In this case it might have a stub for IPersistFile::Save in it's VTable and when it is called it creates an instance of IPersistFile and calls that method.
ToutEnMasm,
I don't know if this will help,...I've been reading Don Box's "Essential COM" lately, and he has a chapter on the Standard Marshaling Architecture. COM uses the Object Remote Procedure Call protocol for all cross-apartment access (all remoting). All remote COM activation calls (like CoCreateInstance or CoGetClassObject) use a Proxy and Stub architecture that the COM library manages. You probably know all that. Anyway, I was googling around and found this site: http://www.hsc.fr/ressources/articles/win_net_srv/chap_msrpc.html. I don't speak French, but most of the articles at this site are in FRENCH.
Also, there is a reasonabvly good explanation of the COM+ Standard Marshaling here: http://www.codeguru.cn/VC&MFC/InsideCOM+/ch15a.htm and a description of the COM+ Network Protocol here: http://www.codeguru.cn/VC&MFC/InsideCOM+/ch19a.htm. Both are in English.
Hello,
Thanks for answer that are useful.
I break my teeth (french expression) in this sort of CLSID
Quote
Windows Registry Editor Version 5.00
[HKEY_CLASSES_ROOT\CLSID\{042C3298-4790-4E9C-98C8-CC65629CBB8C}]
@="Cyberlink RipMVR Setting"
[HKEY_CLASSES_ROOT\CLSID\{042C3298-4790-4E9C-98C8-CC65629CBB8C}\InprocServer32]
@="C:\\Program Files\\CyberLink\\PowerProducer\\RipMVR.dll"
"ThreadingModel"="Both"
cocreateinstance connect OK with the Iunknown Interface,THE problem is when I want to release the interface,I got only a crash.
Quote
.data
CLSID_RipMVR GUID <042C3298h,4790h,4E9Ch,<98h,0C8h,0CCh,65h,62h,9Ch,0BBh,8Ch>>
IID_Iunknown GUID <0H,0H,0H,<0C0H,0H,0H,0H,0H,0H,0H,046H>>
.code
invoke CoInitializeEx,NULL, COINIT_APARTMENTTHREADED
.
.
...cocreateinstance ... CLSID_RipMVR .... IID_Iunknown
return S_OK
But ...
Release go to crash
That i want is,just connect to the object,test if he can connect or not to one interface (Iunknown is useful in this case) and Release without problem.
If there is too much protections to do this,test is not made.
Help please ?
COM Threading Models are an endless source of confusion. I think the only person on the planet that isn't confused by it is Don Box,...anyway,...
You should read: http://msdn.microsoft.com/en-us/library/ms809971.aspx, this is an explanation of COM Threading Models at MSDN.
A number of things to keep in mind:
When you call CoInitializeEx with the COINT_APARTMENTTHREADED, you are entering a newly created STA (Single-Threaded Apartment). This is incompatible with the registry value for the Class's threading mode (ThreadingModel="Both", means that the object can execute in either a Single-Threaded or Multi-Threaded apartment)l. When that happens the COM library creates a proxy. Here, I quote directly from Don Box:
"Each thread that calls CoInitializeEx with COINIT_APARTMENTTHREADED executes in a private apartment that no other thread can enter. If the client's apartment is incompatible with the CLSID's Threading Model, then in-process activation requests for that CLSID will force COM to silently instantiate the object in a distinct apartment, and a proxy will be returned to the client. Implementors that mark their classes as either ThreadingModel="Free" or ThreadingModel="Both" are making the statement that instances of their class may run in the MTA, which means that a single instance of the class may be accessed concurrently. If a class is marked ThreadingModel="Both" and an activation request is made from an STA-based thread, the object will live in an STA. This means that the worker threads (which will run in the MTA) must access the object using interapartment method calls,..."
...And, if this wasn't confusing enough already,...it gets worse,...
More background information, from Don Box (Essential COM, 1998):
"COM allows interface pointers to be passed across apartment boundaries using a technique called marshaling. Note that because COM deals exclusively with interface pointers, not the objects themselves, this marshaled state does not represent the state of the object, but rather the serialized state of an apartment-independent reference to the object. These marshaled object references simply contain connection establishment information that is completely independent of the object's state. Normally, interface pointers are marshaled implicitly as part of the normal operation of COM. When an in-process activation request is made for a class with an incompatible threading model, COM implicitly marshals the interface from the object's apartment and unmarshals a proxy in the client's apartment. When method calls are performed on proxies, any interface pointers that are passed as method parameters will be marshaled in order to make the object references available in both the client's and the object's apartments."
You should read this MSDN reference : http://msdn.microsoft.com/en-us/library/ms678428(VS.85).aspx to CoMarshalInterface.
Don Box explains further:
"CoMarshalInterface takes an interface pointer on input and writes the serialized representation of the pointer to a caller provided byte stream. This byte stream can then be passed to another apartment, where the CoUnmarshalInterface API function uses the byte stream to return an interface pointer that is semantically equivalent to the original object yet can be legally accessed in the apartment that executes the CoUnmarshalInterface call. CoMarshalInterface also allows the caller to specify the marshaling semantics using the following marshal flags:
typedef enum tagMSHLFLAGS {
MSHLFLAGS_NORMAL, // marshal once, unmarshal once
MSHLFLAGS_TABLESTRONG, // marshal once, unmarshal many
MSHLFLAGS_TABLEWEAK, // marshal once, unmarshal many
MSHLFLAGS_NOPING = 4, // supress distributed garbage collection
} MSHLFLAGS;
...At this point, you're probably wondering, where is this MANIAC going with this INSANELY LENGTHY, SEEMINGLY RANDOM TECHNICAL EXPLANATION,....
Well, as it turns out, for various reasons, the external reference count that the proxy holds (and transmits with the marshaled object header byte stream) and the actual AddRef/Release reference count that the object may implement can differ significantly. COM can be maddening in this respect.
...at this point, I'm guessing that you are probably thoroughly disgusted with COM,...
...but, there's more,...alot more,...in fact, it gets pretty exciting at this point, because, you now know how to solve your problem.
... and, if you need more information, there's an entire chapter on 'Standard Marshaling Architecture' that attempts to describe COM proxies and object reference counts.
"When an object does not implement the IMarshal interface, all references to the object will be standard marshaled. When (the COM Library calls) CoMarshalInterface and determines that an object wishes to use standard narshaling, a special COM object called the stub manager is created." It goes on and on,...
...you could save me alot of typing by getting yourself a copy of Don Box's book. It is by far the best reference on the subject. I've worn my copy out.
Title: "ESSENTIAL COM",
Author: Don Box
Copyright: 1998
Publisher: Addison-Wesley Longman, Inc.
ISBN: 0-201-63446-5
Paperback, 440 pages
Hello,
Quote
I'm guessing that you are probably thoroughly disgusted with COM,...
No,No I am just searching a way to solve this and follow with interest this post.
The stub manager will be responsible of the trouble ?
Perhaps searching a sample ...
Actually, I'm a little confused by this section (Lifecycle Management and Marshaling) in Don Box's book, because I've never encountered the situation in real life. But, I'll try to summarize. (Quotes are Don Box.)
"The stub manager is created the first time CoMarshalInterface is called on an object identity. The stub manager holds outstanding references to the object it represents, and the stub manager stays alive as long as there is at least one outstanding external reference to the stub. These external references are usually proxies, although marshaled object references are counted as well, as they represent potential proxies. When all external references ti the stub manager are destroyed, the stub manager deletes itself and releases all references it holds to the actual object. This default behavior exactly simulates the normal in-process semantics of AddRef and Release."
Box then goes on to describe in excruciating detail the operation of COM's distributed garbage collection algorithm and the RPC messages associated with it.
"The stub manager keeps track of how many external references are outstanding. When the stub is created , this count begins at zero. When a call to CoMarshalInterface is made using MSHLFLAGS_NORMAL, this count is increased by some number 'n' that is written to the marshaled object reference. When the proxy manager unmarshals the reference, it adds 'n' to its count of held references. If CoUnmarshalInterface is called on a proxy manager to pass a copy of the reference to another apartment, the proxy manager is free to give out some number of references in order to initialize the second proxy. If a proxy has only one remaining reference, it must go back to the stub manager to request additional references."
"It is often useful to store marshaled interface references in a central location that can be accessed by one or more clients. The Running Object Table used by some moniker implementations is the canonical example of this. If the marshaled interface pointer were to be created using MSHLFLAGS_NORMAL, then one client could ever unmarshal the object reference. If multiple clients are expected to unmarshal the object reference, then the reference needs to be marshaled using either MSHLFLAGS_TABLESTRONG or MSHLFLAGS_TABLEWEAK. In either case, the marshaled object reference can be unmarshaled mukltiple times."
Then, Don Box goes on to describe the difference in reference counting methods that the stub manager implements when either the MSHLFLAGS_TABLESTRONG or MSHLFLAGS_TABLEWEAK Marshaling Flags are used. This stuff is incredibly tedious and seems slightly ridiculous to me, and if you think it's important, I can provide more Don Box. Box mentions a COM function, CoLockObjectExternal, http://msdn.microsoft.com/en-us/library/ms680592(VS.85).aspx by which you can access the external reference count of the stub manager, and either increment or decrement the stub manager's external reference count. Another COM function, CoDisconnectObject, http://msdn.microsoft.com/en-us/library/ms680756(VS.85).aspx allows object implementors to explicitly destroy the stub manager irrespective of the number of outstanding object references. Both CoLockObjectExternal and CoDisconnectObject must be called from within the process of the actual object and cannot be called on a proxy.
Also, it's entirely possible that the problem is something alot simpler.
You should definately change your CoInitializeEx flag to COINIT_MULTITHREADED. Don Box, again: "If the client's apartment is compatible with the CLSID's threading model,then all in-process activation requests for that CLSID will instantiate the object directly in the apartment of the client This is by far the most efficient scenario, as no intermediate proxy is needed."
" Note that to pass a pointer from a thread executing in an MTA to another thread executing in the same apartment, no marshaling calls are required."
In the section of his book where he describes IUnknown reference counting and its pitfalls, he lists a set of rules that apply to clients using COM interface pointers; these are common situations that require calls to the Release method: (1) Prior to overwriting a non-null local variable or data member, (2) Prior to leaving the scope of a non-null local variable, (3) When callee overwrites an [in, out] parameter of a method or function whose initial value is non-null. Note that [out] parameters are assumed to be null on input and must never be released by the callee, (4) Prior to overwriting a non-null data memberof an object, (5) Prior to leaving the destructor of an object that has a non-null interface pointer as a data member.
Also, maybe this is helpful: "If a DLL is unloaded while there are outstanding references to class objects, subsequent calls to even the Release method would cause the client process to crash." This is for an In-Process Server.
Also, you might find that using class monikers to activate your COM class interfaces will be more useful. http://msdn.microsoft.com/en-us/library/ms688618(VS.85).aspx
...Hope you figure it out,...
Hello,
The answer is here:
Quote
Also, you might find that using class monikers to activate your COM class interfaces will be more useful
It is what i made,with
Quote
UseMoniker PROC pclsid:DWORD
Local bindOpts:BIND_OPTS2
Local retour:DWORD
ZEROLOCALES retour
mov retour,-1 ;CreateClassMoniker or CreateBindCtx failed
mov bindOpts.cbStruct,sizeof bindOpts
invoke CreateBindCtx,NULL,addr ppvIBindCtx
.if eax == S_OK
;IBindCtx GetBindOptions,addr bindOpts
invoke CreateClassMoniker,pclsid,addr ppvIMoniker
.if eax == S_OK
IMoniker BindToObject,ppvIBindCtx,NULL,addr IID_IUnknown,addr ppvItest
.if eax == S_OK && ppvItest != 0
Itest Release
.endif
IMoniker Release
.endif
IBindCtx Release
.endif
FindeUseMoniker:
mov eax,retour
ret
UseMoniker endp
I put the adress of the CLSID in pclsid , it is the one (see upper post) that crashes at Release and follow it with the debugger.
connect S_OK
Release ................
don't crashusing class monikers is the more secure method to connect COM interface,explain is contained in the SDK.
Quote
IMoniker::BindToObject
Uses the moniker to bind to the object it identifies. The binding process involves finding the object, putting it into the running state if necessary, and supplying the caller with a pointer to a specified interface on the identified object.
Many thanks for help
...sorry for all the misdirection.
I have crashed a DirectX application by calling Release as the application is terminating (processing the WM_CLOSE message), and the application crashes, like yours. Eliminating the call to Release keeps the application from crashing, but, it is unknown why the reference count is already zero and the DLL has apparently unloaded.
I assume that you are enumerating through your registry's CLSIDs, and this only happens occasionally. As far as I know, there is no straightforward way to check the reference count.
...anyway, good luck with your project.
Hello,
Don't be sorry,it was ways to explore before finding the good.
But now I have made a test of browsing the many clsid in my registry,I can tell you that the moniker can do manything not explain in the SDK.
Some interfaces that was bad installed have displayed a dialog box to finish the work and I haven't get a single crash,I have made no test with CLSID not installed (filtered) .
Another thing is that there isn't use of the CLSTX constant to connect.That is better,vista have a list of ten of those constants and it will be not easy to find the good one or the good group.
Try it in your application that have crashed,and you will surely have a good surprise.
It's REALLy EMBARRASSING to admit this,...but, I've never actually used Monikers in my code projects (although the intent was there). I've read about them and am aware of how useful they are, especially in a network environment.
In Don Box's book, he devotes about a dozen pages to describing the various types and typical usage. As he says in the book's forward: "Monikers are more powerful than you think." Also, he says that the IMoniker inrerface is one of the more complex COM interfaces.
You ought to investigate the ROT, or Running Object Table, which "is a facility of the SCM (Service Control Manager) that maps arbitrary monikers onto running instances on the local host machine". The COM API GetRunningObjectTable (http://msdn.microsoft.com/en-us/library/ms695276(VS.85).aspx) returns an IRunningObjectTable interface pointer into the SCM. Item Monikers and File Monikers are used with the ROT for convient access to registered COM Objects.
This might provide you with more information; it's the section on Monikers from the original Microsoft COM Specification:
(http://groups.csail.mit.edu/medg/ftp/emjordan/COM/CH11%20MON.DOC).
This COM API might also be useful: MkParseDisplayName (http://msdn.microsoft.com/en-us/library/ms691253(VS.85).aspx)
And, finally, Box describes how Monikers can be composited to allow object hierarchies to be navigated based on a textual description of a path. I can't say that I really understand how this works specifically. Box leaves alot of information about the algorithms used internally by the various Moniker types unstated.
What amazes me is that you are writing a browser for COM classes in ASSEMBLY. If I tried to do that in C++, using Visual Studio, I'd be having a hell of a time. I would develop some bizarre dementia, and would be running around with my hair on fire.
Making some test,I have made it better.
At this time of my experiment , all interfaces don't accept to connect with the monikers method.
But,when the method failed,there is no crash.This a good thing that allow to write a secure method to connect to interfaces.
The GetInterfaceFromProgId proc call UseMoniker to finish the work.In case of failed connection,the normal cocreateinstance is called.All tests are made with the Iunknown interface.
I have added the CLSTX values in the BindOptions,but I am not sure of what i am doing.
Quote
;pProgId pointeur sur une chaine ProgId "Microsoft.ISAM.OLEDB.1.1"
;pIID pointeur sur un GUID IID_ nommant l'interface
GetInterfaceFromProgId PROC pProgId:DWORD,pIID:DWORD
LOCAL wszProgID[MAX_PATH]:word
Local resultat:SDWORD
LOCAL ppv:Dword,retour,pchaine
LOCAL clsid :GUID
mov retour,0
invoke MultiByteToWideChar,CP_ACP,MB_PRECOMPOSED,pProgId,-1,addr wszProgID,sizeof wszProgID
invoke CLSIDFromProgID,addr wszProgID,addr clsid
.if eax == S_OK
invoke UseMoniker,addr clsid,pIID
mov resultat,eax
.if resultat > 0
PuPo retour,eax
.endif
.endif
mov eax,retour
RET
GetInterfaceFromProgId endp
;################################################################
UseMoniker PROC pclsid:DWORD,pIID:DWORD
Local bindOpts:BIND_OPTS2
Local ppv:DWORD
Local retour:DWORD
ZEROLOCALES retour
mov retour,-1 ;CreateClassMoniker failed
mov bindOpts.cbStruct,sizeof bindOpts
IBindCtx GetBindOptions,addr bindOpts
mov bindOpts.dwClassContext,CLSCTX_INPROC_SERVER OR CLSCTX_INPROC_HANDLER OR CLSCTX_LOCAL_SERVER
IBindCtx SetBindOptions,addr bindOpts
;ppvIBindCtx condition de départ
invoke CreateClassMoniker,pclsid,addr ppvIMoniker
.if eax == S_OK
mov eax,pIID
IMoniker BindToObject,ppvIBindCtx,NULL,pIID,addr ppv
.if eax == S_OK
;le clsid est gérable comme ça
.if ppv != 0
PuPo retour,ppv
.endif
.else
;non traité par BindToObject
invoke CoCreateInstance,pclsid,NULL,
CLSCTX_INPROC_SERVER OR CLSCTX_INPROC_HANDLER OR CLSCTX_LOCAL_SERVER,
pIID,addr ppv
.if eax == S_OK
PuPo retour,ppv
.else
mov retour,0
.endif
.endif
IMoniker Release
.endif
FindeUseMoniker:
mov eax,retour
ret
TraiteErreur:
;WinError.h
.if eax == E_OUTOFMEMORY
mov edx,0
.elseif eax == MK_E_NOOBJECT
mov edx,0
.elseif eax == MK_E_EXCEEDEDDEADLINE
mov edx,0
.elseif eax == MK_E_CONNECTMANUALLY
mov edx,0
.elseif eax == MK_E_INTERMEDIATEINTERFACENOTSUPPORTED
mov edx,0
.elseif eax == STG_E_ACCESSDENIED
mov edx,0
.elseif eax == CLASS_E_CLASSNOTAVAILABLE
mov edx,0
.else
mov edx,1
.endif
retn
UseMoniker endp
;################################################################
ToutEnMasm,
I stumbled upon several items that might be of interest.
Here is a Larry Osterman blog that explains COM activation, and in particular, the CLSCTX flags. http://blogs.msdn.com/larryosterman/archive/2004/10/12/241420.aspx. This blog entry also has information on COM threading models: http://blogs.msdn.com/larryosterman/archive/2004/04/28/122240.aspx. You'll notice that in my original explanation of threading models and the proxy-stub architecture, I was in error about your STA thread the the ThreadingModel=Both key value in the registry.
Also, there is an old two part series in MSJ (Microsoft Systems Journal, 1999) called the Universal Delegator, by Keith Brown: January http://www.microsoft.com/msj/0199/intercept/intercept.aspx, and,
Febuary http://www.microsoft.com/msj/0299/intercept2/intercept2.aspx. Download the Delegator code: http://download.microsoft.com/download/0/6/7/0678184e-905e-4783-9511-d4dca1f492b4/delegate2.exe
Not very easy to find what can be done with the delegator.
The source code is a dll and the sample of use a ... dll.
Not very clear for me.
I have see that some hook can be made and interceptions (of what ?) can be made.
seems to replace the Ifactory
Quote
The delegator has a custom class object that implements this interface (instead of the more common IClassFactory). This allows you to provide initialization data during construction
Like that seems to be the starting point of ATL ??.
Trying to see what others langage do , ihave found this.
http://www.csharphelp.com/archives/archive160.html
Can masm do a little like that ?