The MASM Forum

General => The Campus => Topic started by: mabdelouahab on April 16, 2015, 05:50:24 PM

Title: COM Events
Post by: mabdelouahab on April 16, 2015, 05:50:24 PM
Hi everyone
I just wanted to know how to deal with COM Object
I made a simple example by VB, Then I made another example by MASM32, linking programs..
The purpose of this work is to know how to link with the Com Object with Events.
It didn't work with me.
To see what happens I added some modifications to procedures "QueryInterface,AddRef,Release,..."
When I call the procedure "FindConnectionPoint.Advise" I found that the Class send requests to QueryInterface
What is exactly required to success of the procedure Advise?
Title: Re: COM Events
Post by: dedndave on April 16, 2015, 08:57:24 PM
Quote from: mabdelouahab on April 16, 2015, 05:50:24 PM
I just wanted to know how to deal with COM Object

the answer to that is quite involved, to say the least
furthermore, to set off reading about COM is difficult
they use a lot of terminology that doesn't make sense unless you already know about COM   :lol:

i'll try to cover a few points to get you started....

first, before using COM in a program, you must CoInitialize (there are different versions of this in some cases)
when done, CoUninitialize must be called
i generally put these at the beginning and end of the program
start:  INVOKE  CoInitialize,NULL

;rest of program

        INVOKE  CoUninitialize
        INVOKE  ExitProcess,0


next, access to functions are implemented through what are essentially "vector tables"
by now, i'm sure you're familiar with PROTOtypes
well - the vectors in a COM interface table each have different prototypes, in a manner of speaking
qWord has provided us with a very nice macro to help us
there are others, but i like qWord's because using it is a little easier to understand
;METHOD macro by qWord

METHOD  MACRO   name,args:VARARG
        LOCAL   _type1,_type2
        _type1  TYPEDEF PROTO args
        _type2  TYPEDEF PTR _type1
        EXITM   <name _type2 ?>
        ENDM


now, in the past, i have used an IDispatch interface, so i already have the interface structures made
in this case, it's for the IShellDispatch interface
IShellDispatch is an IDispatch interface
and, IDispatch interface is an IUnkown interface
that probably seems very confusing - lol

i think it's safe to say that most COM interfaces are of the type IUnknown
that means, among other things, that the first few functions are of a common set
notice that qWord's METHOD macro is used to prototype a structure of vectors
;IUnknown interface vTable (structure)

IUnknown STRUCT
  METHOD(QueryInterface, _this:LPVOID,riid:LPVOID,ppvObj:LPVOID)
  METHOD(AddRef,         _this:LPVOID)
  METHOD(Release,        _this:LPVOID)
IUnknown ENDS


now, to make more sense of what i was saying before,
the IDispatch interface can be made by simply referencing IUnknown
;IDispatch interface vTable (structure)

IDispatch STRUCT
    IUnknown                 <>
  METHOD(GetTypeInfoCount, _this:LPVOID,pctinfo:LPVOID)
  METHOD(GetTypeInfo,      _this:LPVOID,iTInfo:UINT,lcid:LCID,ppTInfo:LPVOID)
  METHOD(GetIDsOfNames,    _this:LPVOID,riid:LPVOID,rgszNames:LPOLESTR,cNames:UINT,lcid:LCID,rgDispId:LPVOID)
  METHOD(dInvoke,          _this:LPVOID,dispIdMember:DWORD,riid:LPVOID,lcid:LCID,wFlags:DWORD,pDispParams:LPVOID,pVarResult:LPVOID,pExcepInfo:LPVOID,puArgErr:LPVOID)
IDispatch ENDS

all IDispatch interfaces share these common elements

IShellDispatch may now reference IDispatch
in the case of VARIANT structures, i have broken them down into individual DWORD's
this makes functions with VARIANT arguments easier to use in assembly language
;IShellDispatch interface vTable (structure)
;       vDir VARIANT struct = vtDir:DWORD,vD0:DWORD,vstrDir:LPVOID,vDV0:DWORD
;vRootFolder VARIANT struct = vtRoot:DWORD,vR0:DWORD,vstrRoot:LPVOID,vRV0:DWORD

IShellDispatch STRUCT
    IDispatch                <>
  METHOD(Application,      _this:LPVOID,ppid:LPVOID)
  METHOD(Parent,           _this:LPVOID,ppid:LPVOID)
  METHOD(NameSpace,        _this:LPVOID,vtDir:DWORD,vD0:DWORD,vstrDir:LPVOID,vDV0:DWORD,ppsdf:LPVOID)
  METHOD(BrowseForFolder,  _this:LPVOID,Hwnd:DWORD,lpTitle:LPVOID,Options:DWORD,vtRoot:DWORD,vR0:DWORD,vstrRoot:LPVOID,vRV0:DWORD,ppsdf:LPVOID)
  METHOD(Windows,          _this:LPVOID,ppid:LPVOID)
  METHOD(Open,             _this:LPVOID,vtDir:DWORD,vD0:DWORD,vstrDir:LPVOID,vDV0:DWORD)
  METHOD(Explore,          _this:LPVOID,vtDir:DWORD,vD0:DWORD,vstrDir:LPVOID,vDV0:DWORD)
  METHOD(MinimizeAll,      _this:LPVOID)
  METHOD(UndoMinimizeALL,  _this:LPVOID)
  METHOD(FileRun,          _this:LPVOID)
  METHOD(CascadeWindows,   _this:LPVOID)
  METHOD(TileVertically,   _this:LPVOID)
  METHOD(TileHorizontally, _this:LPVOID)
  METHOD(ShutdownWindows,  _this:LPVOID)
  METHOD(Suspend,          _this:LPVOID)
  METHOD(EjectPC,          _this:LPVOID)
  METHOD(SetTime,          _this:LPVOID)
  METHOD(TrayProperties,   _this:LPVOID)
  METHOD(Help,             _this:LPVOID)
  METHOD(FindFiles,        _this:LPVOID)
  METHOD(FindComputer,     _this:LPVOID)
  METHOD(RefreshMenu,      _this:LPVOID)
  METHOD(ControlPanelItem, _this:LPVOID,bstrDir:LPVOID)
IShellDispatch ENDS


in many cases - using the features provided requires accessing yet another interface level
for example, if we want to use an IShellDispatch::NameSpace Folder object, we need another interface
it, too, is an IDispatch interface, so....
;IShellDispatch::NameSpace Folder object interface vTable (structure)
;   vItem VARIANT struct = vtItem:DWORD,vI0:DWORD,vdwItem:DWORD,vIV0:DWORD
;vOptions VARIANT struct = vtOpt:DWORD,vO0:DWORD,vdwOpt:LPVOID,vOV0:DWORD

Folder STRUCT
    IDispatch            <>
  METHOD(getTitle,     _this:LPVOID,pbs:LPVOID)
  METHOD(Application,  _this:LPVOID,ppid:LPVOID)
  METHOD(Parent,       _this:LPVOID,ppid:LPVOID)
  METHOD(ParentFolder, _this:LPVOID,ppsf:LPVOID)
  METHOD(Items,        _this:LPVOID,ppid:LPVOID)
  METHOD(ParseName,    _this:LPVOID,bstrName:LPVOID,ppid:LPVOID)
  METHOD(NewFolder,    _this:LPVOID,bstrName:LPVOID,vtOpt:DWORD,vO0:DWORD,vdwOpt:LPVOID,vOV0:DWORD)
  METHOD(MoveHere,     _this:LPVOID,vtItem:DWORD,vI0:DWORD,vdwItem:DWORD,vIV0:DWORD,vtOpt:DWORD,vO0:DWORD,vdwOpt:LPVOID,vOV0:DWORD)
  METHOD(CopyHere,     _this:LPVOID,vtItem:DWORD,vI0:DWORD,vdwItem:DWORD,vIV0:DWORD,vtOpt:DWORD,vO0:DWORD,vdwOpt:LPVOID,vOV0:DWORD)
  METHOD(GetDetailsOf, _this:LPVOID,vtItem:DWORD,vI0:DWORD,vdwItem:DWORD,vIV0:DWORD,iColumn:DWORD,pbs:LPVOID)
Folder ENDS


a note about GUID's (including CLSID's and IID's)
there is a structure defined in Hutch's windows.inc, called "GUID"
        .DATA
        ALIGN   4

CLSID_Shell         GUID <13709620h,0C279h,11CEh,<0A4h,9Eh,44h,45h,53h,54h,0,0>>
IID_IShellDispatch  GUID <0D8F015C0h,0C278h,11CEh,<0A4h,9Eh,44h,45h,53h,54h,0,0>>

IID_Folder          GUID <0BBCBDE60h,0C3FFh,11CEh,<83h,50h,44h,45h,53h,54h,0,0>>
IID_FolderItem      GUID <0FAC32C80h,0CBE4h,11CEh,<83h,50h,44h,45h,53h,54h,0,0>>
IID_FolderItems     GUID <744129E0h,0CBE5h,11CEh,<83h,50h,44h,45h,53h,54h,0,0>>
IID_IShellFolder    GUID <214E6h,0,0,<0C0h,0,0,0,0,0,0,46h>>


i'll let you chew on all that before we actually use the interfaces   :P
Title: Re: COM Events
Post by: dedndave on April 16, 2015, 10:14:19 PM
a simplified example of using a COM interface...

1) CoInitialize
2) CoCreateInstance
this gives you an instance of the interface, in the form of a pointer to a vector table
you store this pointer and use it whenever a call is made
3) call the function or "method"
you pass a pointer, and it's contents - lol
4) Release - when you're done with the instance, release it
5) CoUninitialize

now, that's a simple example - in most cases, it's much more involved
we want to keep it simple to help you understand the sequence of events

        .DATA?
        ALIGN   4

pvShell    LPVOID ?

        .CODE

Start:  INVOKE  CoInitialize,NULL

;notice that pvShell is filled by this call
;normally, we would examine the return value to verify success before proceeding
;again, we're going to keep it simple

    INVOKE  CoCreateInstance,offset CLSID_Shell,NULL,CLSCTX_INPROC_SERVER,offset IID_IShellDispatch,offset pvShell

;now, to make a call, we need the "THIS" pointer content
;in this example, we make a NameSpace call that actually creates another interface instance (pvFolder)
;we aren't going to use that interface (or release it) - we just want to demonstrate an interface invoke

        mov     edx,pvShell
        mov     ecx,[edx]
        INVOKE  IShellDispatch.NameSpace[ecx],edx,VT_BSTR,0,offset bstrPathTarget,0,offset pvFolder

;when we're done using the interface, we Release it (this is a standard IUnknown procedure)

        mov     edx,pvShell
        mov     ecx,[edx]
        INVOKE  IShellDispatch.Release[ecx],edx

;now, we want to exit, so....

        INVOKE  CoUninitialize
        INVOKE  ExitProcess,0
Title: Re: COM Events
Post by: mabdelouahab on April 16, 2015, 10:14:53 PM
Hello my teacher dave.
I thank you for the valuable information
But my question is much simpler
Why not work with me  Advise correctly; IConnectionPoint.Advise doesn't work with me

In the first of the program I call the method "Class1. IsMe2(a As String)" without Events، And then I called it with Events
the method "Class1. IsMe2(a As String)" will show a message and then launch Events
Public Sub IsMe2(a As String)
    MsgBox "Is Me sec[" & a & " ]"
    RaiseEvent Ev01
End Sub

To link events, I made mrthod AdviseEvents, which links ConnectionPoint then call Advise to correlate Events
I have the problem of expressing the problem
Title: Re: COM Events
Post by: dedndave on April 16, 2015, 10:20:56 PM
i've never played with connection points
it will take me some time to do some reading and understand it better   :t

https://msdn.microsoft.com/en-us/library/windows/desktop/ms694318%28v=vs.85%29.aspx (https://msdn.microsoft.com/en-us/library/windows/desktop/ms694318%28v=vs.85%29.aspx)

i should be able to get back to this later today
Title: Re: COM Events
Post by: mabdelouahab on April 16, 2015, 10:50:56 PM
I'm sorry... ; I forgot to add REG.BAT :biggrin:
To work my attachment, open "\vbexmple" and then run Reg.bat  to register the Library
Then execute the example in  "\TestEvents"
Title: Re: COM Events
Post by: Zen on April 17, 2015, 05:16:04 AM
Hi, MABDELOUAHAB,
I read through the posts in this thread, and I read through the source code that you provided.
Unfortunately, I'm not experienced in programming with Visual Basic, so, I didn't understand the VB source code.
But, neither prj001 nor prj008 (in the vbexample directory) launched on my machine. And, there is no compiled executable in the TestEvents directory (although there is a compiled Obj file).
I don't quite see the point of this whole exercise, though. The Visual Basic language and, presumably, the VB compiler, are not really adequate for handling COM objects. COM evolved from C++, and, it's fairly complicated with Visual Studio, using the C++ language. I have heard unsubstantiated rumors, though, that it is possible to instantiate a COM object and execute its methods in a Visual Basic program. But, you're doing it the hard way.
Based on what I've seen with the example you've provided, I can't even tell if the vbexamples, prj001 and prj008 have linked correctly. Nothing happens when I try to run these programs.
If it were me, I'd attempt writing the whole project in MASM assembly language first. At least the MASM Forum members could understand the source code, and diagnose the problem.
In reading through the assembly language portion of your project,...I can see that you've got problems. Maybe you should rethink the whole approach.
MASM Forum member, japheth, is famous for his assembly language versions of simple COM servers and various other COM components. In fact, he used to have a website dedicated to COM and assembly language,...and a number of other very useful utilities,...but, his website no longer exists. I have a number of his example projects that I can upload here if you are interested. He structured his COM interfaces in an entirely different way than you did,
...although you do seem to understand the principles.
Here is MSDNs section about: Component Object Model (COM) (https://msdn.microsoft.com/en-us/library/windows/desktop/ms680573(v=vs.85).aspx)
...And you might find this helpful: Translating to Visual Basic (Translating COM Object Syntax for Programming Languages) (https://msdn.microsoft.com/en-us/library/windows/desktop/ms682260(v=vs.85).aspx)
Title: Re: COM Events
Post by: mabdelouahab on April 17, 2015, 07:28:01 AM
Hi Zen;
prj001 is ActiveX EXE Component; not executable, but it  wait until the the creation of objects (Jast an TypeLibrary), Just registered by REG.Bat
prj001 Contains an object CLASS1 implement 2 dispatch _Class1 (Default) and __Class1( sink objects)
If I wanted that I only work on CLASS1 without events I've been using (masm) "CreateClass Proc", Then I call any method of CLASS1 like "Class1. IsMe2" ;******************************************** Class1. IsMe2(a As String)
lea ecx, bs
push ecx
        mov edx, Inst_Class1
        push edx   
        mov edx,[edx]   
        CALL dword ptr [edx+40]  ;IsMe2

But if I wanted to work on CLASS1 withe Events It must be create an interface "__Class1 struct" with "CreateInterface proc" then advise it with IConnectionPoint.Advise For the host Object call procedures of this interface when an events is raised

in my attachment , do not use anything in " "\vbexmple"",  just use REG to register the typelibrary
then return to the masm programe "\TestEvents", and run it to see what hapen 
Title: Re: COM Events
Post by: dedndave on April 17, 2015, 12:24:38 PM
a lot of material to cover - i'm afraid i'm a bit overwhelmed - lol

however, i did disassemble the prj008.exe file
and, i used the resource hacker to examine the resources

much of the COM code resides in the MSVBVM60.DLL file   :(
Title: Re: COM Events
Post by: Zen on April 18, 2015, 05:22:18 AM
MABDELOUAHAB,
This is your 'reg' file. Tell me what is supposed to happen when I execute this file.
prj001.exe /RegServer
...You know,...the way you've structured this whole project is just annoying. Do you really think I want to register a COM server (that doesn't work) on my machine ???
Regsvr32 (https://technet.microsoft.com/en-us/library/bb490985.aspx)
How to register an ActiveX control (.ocx) manually (https://support.microsoft.com/en-us/kb/146219/)
Title: Re: COM Events
Post by: mabdelouahab on April 18, 2015, 05:44:55 AM
Zen
prj001.exe is just an example, Give me any example of a Com Typelibrary contains an Object with Events I'm working on it, My goal is to know how it works IConnectionPoint.Advise.
Title: Re: COM Events
Post by: Zen on April 18, 2015, 05:49:52 AM
MABDELOUAHAB,
Do you know what the OLE/COM Object Viewer (https://msdn.microsoft.com/en-us/library/d0kh9f4c.aspx) is ? When you have correctly registered a COM server, the type library, and the COM class, and the various COM interfaces are displayed in the OLE/COM Object Viewer. If I used the Regsvr32 utility to register your COM component, and it worked correctly (which it doesn't), your COM component could be accessed by the OLE/COM Object Viewer and the information about your type library and any registered COM classes and interfaces would be displayed on the  OLE/COM Object Viewer interface window.
Title: Re: COM Events
Post by: Zen on April 18, 2015, 06:12:00 AM
MABDELOUAHAB,
Maybe this will help. It's the example I mentioned in my original post, contributed by Japheth. It's written completely in MASM assembly language.
Title: Re: COM Events
Post by: mabdelouahab on April 18, 2015, 09:05:51 AM
Quote from: Zen on April 18, 2015, 06:12:00 AM
MABDELOUAHAB,
Maybe this will help. It's the example I mentioned in my original post, contributed by Japheth. It's written completely in MASM assembly language.

Zen I Thanks for the help but the example does not contain any events.
I found another very nice example  in MASM, Contains an object IMyCom2, store Value and read it (get_Value/set_Value), and then fire an event XMax if the value  is greater than 100
I worked with him without Events, But when I want to link to the event, gave me the same problem in the first example

CreateClass OK
IMyCom2. Set_Value 107 OK
IMyCom2. Get_Value m_Value=107 OK Press any key to continue ...

QueryInterface IConnectionPointContainer OK
FindConnectionPoint OK
_QIf<000000003,00000h,00000h<0C0h,000h,000h,000h,000h,000h,000h,046h>>_QIf
_QIf<0ECC8691B,0C1DBh,04DC0h<085h,05Eh,065h,0F6h,0C5h,051h,0AFh,049h>>_QIf
_QIf<000000003,00000h,00000h<0C0h,000h,000h,000h,000h,000h,000h,046h>>_QIf
_QIf<00000001B,00000h,00000h<0C0h,000h,000h,000h,000h,000h,000h,046h>>_QIf
_QIf<000000000,00000h,00000h<0C0h,000h,000h,000h,000h,000h,000h,046h>>_QIf2
AddRef
_QIf<000000018,00000h,00000h<0C0h,000h,000h,000h,000h,000h,000h,046h>>_QIf
_QIf<0334D391F,00E79h,03B15h<0C9h,0FFh,0EAh,0C6h,05Dh,0D0h,07Ch,042h>>_QIf
_QIf<000000040,00000h,00000h<0C0h,000h,000h,000h,000h,000h,000h,046h>>_QIf
_QIf<0334D391F,00E79h,03B15h<0C9h,0FFh,0EAh,0C6h,05Dh,0D0h,07Ch,042h>>_QIf
_QIf<094EA2B94,0E9CCh,049E0h<0C0h,0FFh,0EEh,064h,0CAh,08Fh,05Bh,090h>>_QIf
_QIf<0334D391F,00E79h,03B15h<0C9h,0FFh,0EAh,0C6h,05Dh,0D0h,07Ch,042h>>_QIf
_QIf<077DD1250,0139Ch,02BC3h<0BDh,095h,090h,00Ah,0CEh,0D6h,01Bh,0E5h>>_QIf
_QIf<000000019,00000h,00000h<0C0h,000h,000h,000h,000h,000h,000h,046h>>_QIf
_QIf<04C1E39E1,0E3E3h,04296h<0AAh,086h,0ECh,093h,08Dh,089h,06Eh,092h>>_QIf
Release

Does one tell me what is the meaning of the values of the riid sent to queryinterface Or what should I do to connect events ( MyEventClass  in this example)
Example needs some files, I've sent with attachments (com.zip)
Don't forget reg.bat in "\AsmEvent"
Title: Re: COM Events
Post by: adeyblue on April 18, 2015, 10:35:35 AM
You probably need to implement IDispatch.Invoke. In the first example, Invoke is called with the DispId of the Ev1 function, but since Invoke returns E_NOTIMPL, nothing else happens*

It can be implemented using Microsoft's helper function (https://msdn.microsoft.com/en-us/library/windows/desktop/ms221366(v=vs.85).aspx), but it needs an ITypeInfo for an implementation of the interface. So the ASM app would need its own typelibrary as well as the one in the VB app.

It can be implemented manually but that involves looking up the function to call from the DispId, unpacking the parameters from the VARIANT array, calling the function, then cleaning up afterwards.

* I translated your ASM app to C++, and that's what happened
Title: Re: COM Events
Post by: mabdelouahab on April 18, 2015, 11:18:36 PM
adeyblue
Quote from: adeyblue on April 18, 2015, 10:35:35 AM
You probably need to implement IDispatch.Invoke. In the first example, Invoke is called with the DispId of the Ev1 function, but since Invoke returns E_NOTIMPL, nothing else happens*
The problem is that my program does not exceed the " IConnectionPoint.Advise" We have yet to call events, Either TypeInfo and  IDispatch.Invoke they are easy to handle.

I noticed that when the program calls the advise, my Interface.QueryInterface receives riid:
<000000003,00000h,00000h<0C0h,000h,000h,000h,000h,000h,000h,046h>>;<0ECC8691B,0C1DBh,04DC0h<085h,05Eh,065h,0F6h,0C5h,051h,0AFh,049h>>;......

First is IID_IMarshal, Second: IID_INoMarshal; IID_IIdentityUnmarshal
I tried to accept the first (),  then I sent new instance of IMarshal object, He sends a request to IMarshal.GetMarshalSizeMax, All this happens in the background And Before passing  IConnectionPoint.Advise ;I don't have enough information

In the example MSDN inserted C++ Event Sinks Sample (https://msdn.microsoft.com/en-us/library/windows/desktop/ms701155%28v=vs.85%29.aspx) , Called CoCreateFreeThreadedMarshaler

Does anyone have information on what happens in the background?


Title: Re: COM Events
Post by: dedndave on April 18, 2015, 11:51:42 PM
this is kind of "advanced" COM, from what i understand
we had a similar issue when we were trying to use COM to zip or unzip a file
we figured out how to write the zip/unzip code, but we haven't really figured out how to know when it's done   :P

i think this is where COM "apartments" come in - and i haven't got that far in the learning curve
so far, i haven't seen too much on events in COM, in the way of ASM code

when you write the code in visual basic, the compiler does a lot of stuff in the background that the programmer doesn't see
Title: Re: COM Events
Post by: Zen on April 19, 2015, 03:17:03 AM
MABDELOUAHAB,
Here is an excellent article that explains COM Events: Understanding COM Event Handling, CodeProject (http://www.codeproject.com/Articles/9014/Understanding%20COM%20Event%20Handling)
Scroll down to the section: Connection Points and Connection Point Containers

If you read that article, you will come to this statement:
Quote from: Understanding COM Event Handling    Visual Basic applications can only handle ActiveX object events through sinks which are dispinterface-based. This is natural both because of the fact that Visual Basic cannot handle non-dispinterface-based events, and also because of the need to handle events fired from any and all ActiveX objects.
    The central point behind this is that while event interfaces need not be dispinterface-based (their methods can be of any signature, the only mandate is that the event interface must also derive from IUnknown), Visual Basic is not able to internally anticipate the design of these custom event interfaces and to generate Sinks for them.
    Furthermore, the types of method return values and parameters must be confined to those that Visual Basic is able to understand and internally process. Hence, the only way to standardize the handling of event interfaces is to require that they be derived from IDispatch, and that the return and parameter types be from a wide but limited ranged set. This set of types is known as the automation-compatible-types.

...So,...apparently, ADEYBLUE was correct. (http://www.conceptart.org/forums/images/ca_smilies/membermade/wtf.gif)

Also, you may find this MSDN reference section informative: COM Interop (Visual Basic) (https://msdn.microsoft.com/en-us/library/6bw51z5z.aspx)

Quote from: DAVE !!!...when you write the code in visual basic, the compiler does a lot of stuff in the background that the programmer doesn't see,...
...Dave is right about this. Seriously,...Dave is ALWAYS right,...except,...of course,...when it concerns Device Contexts,...lol,...:biggrin:

Note: The impression that I get is that Visual Basic syntax is FUNKY (in the Robin Williams sense),...
For those of you who are NOT Visual Basic programmers: Visual Basic Joke, Raymond Chen (http://blogs.msdn.com/b/oldnewthing/archive/2005/09/30/475688.aspx)
Title: Re: COM Events
Post by: jj2007 on April 19, 2015, 03:42:46 AM
Quote from: Zen on April 19, 2015, 03:17:03 AMHere is an excellent article that explains COM Events: Understanding COM Event Handling, CodeProject (http://www.codeproject.com/Articles/9014/Understanding-COM-Event-Handling)

Excellent article indeed :t
If I had unlimited time and no other projects, I would give it a try.
Title: Re: COM Events
Post by: Zen on April 19, 2015, 05:11:29 AM
...So,...I don't see any reason,...given all this pertinent information,...why MABDELOUAHAB's project cannot be correctly implemented,...

(http://1.bp.blogspot.com/-RP6Rv-x72Z0/T_5a4VferNI/AAAAAAAAAtI/YJ6oy7TGv1E/s1600/lost_emoticon.png)
Title: Re: COM Events
Post by: jj2007 on April 19, 2015, 06:03:15 AM
Quote from: Zen on April 19, 2015, 05:11:29 AM
...So,...I don't see any reason,...given all this pertinent information,...why MABDELOUAHAB's project cannot be correctly implemented,...

Me neither. Not trivial but certainly feasible, especially with that rarely well-written article :t
Title: Re: COM Events
Post by: mabdelouahab on April 19, 2015, 06:20:16 AM
dave jj2007 Zen Thank you all

Quote from: Zen on April 19, 2015, 03:17:03 AMHere is an excellent article that explains COM Events: Understanding COM Event Handling, CodeProject (http://www.codeproject.com/Articles/9014/Understanding-COM-Event-Handling)
I am engaged in the project after I read this topic ; But he did not talk about my problem

Am not alone suffered from a problem, see:Advise of Connection Point calls QueryInterface with IID_IMarshal (http://stackoverflow.com/questions/8444551/advise-of-connection-point-calls-queryinterface-with-iid-imarshal)
//Get the pointer to CSink's IUnknown pointer
hr = pSink->QueryInterface (IID_IUnknown,(void **)&pSinkUnk);
if ( !SUCCEEDED(hr) )
{
    return hr;
}

// It is assumed that this should call the QueryInterface with IID__IAdHocPresenceEvents
// Do not understand why this calls the QueryInterface with IID_IMarshal
// Later this becomes reason for not getting event at ClientSink::OnAdHocPresenceQuery
hr = pCntPoint->Advise(pSinkUnk, &dwAdvise);
if ( !SUCCEEDED(hr) )
{
    return hr;
}


Title: Re: COM Events
Post by: Zen on April 19, 2015, 06:49:18 AM
MABDELOUAHAB,
The project that you are attempting to develop is difficult, without a doubt. When I am coding something that is somewhat beyond my capabilities, I just take my time, read and then reread the documentation as many times as necessary, until I understand it thoroughly,...and, then, maybe rethink my approach. Create several different versions to test your techniques. You'll eventually get it,...I can see that you have a fundamental comprehension of the mechanics of COM. I think, exposing your COM object correctly in your Visual Basic application will be the most difficult part of the project.
Just to give you an idea of the effort required: we had a thread last year where one of the MASM Forum members (vertograd) attempted to expose a .NET Framework component from within a MASM assembly language application, (.NET Framework is quite similar to COM, conceptually),...and, it took him a good month to get it to work correctly. This didn't even require any data marshalling, or Interop code. And, that wasn't as difficult a project as yours.
The problem with posting your questions here is that nobody on the MASM Forum has ever attempted something like this (...and lived to tell). So, we're throwing alot of information your way that may not be actually useful.

What I'm wondering is: Why even implement a Visual Basic generated Active X control ? You could write this project entirely in MASM assembly language,...or, combine a MASM generated component with a C or C++ generated component, (or, better yet,...write the entire thing in C++)...or, any one of a number of combinations that would be easier, cleaner, and more compatible with existing Windows Operating Systems. 
...Also,...what compiler are you using for the Visual Basic component ? Are you aware of the inherent limitations imposed by the compiler's operation ?
Title: Re: COM Events
Post by: mabdelouahab on April 19, 2015, 07:28:31 AM
my problem is not in the Visual basic Server, my problem is in the client
because in my secend attachment, (http://masm32.com/board/index.php?topic=4153.msg44134#msg44134 (http://masm32.com/board/index.php?topic=4153.msg44134#msg44134)) the server and the client is written completely in MASM. and give the same problem,  the same problem

I'm not urgent, but I want to clarify the problem only
Title: Re: COM Events
Post by: Biterider on April 19, 2015, 04:00:43 PM
Hi mabdelouahab
In the ObjAsm32 package, there is a project called OCX_LED, that is designed to interface with VB6. AFAIR it implements ConnectionPoints, ConnectionPointContainer, PropertyPages, and so on. Maybe it helps...

Regards, Biterider
Title: Re: COM Events
Post by: mabdelouahab on April 19, 2015, 06:39:48 PM
I found that if de server object is de type InprocServer32 (Dll) like 2 example (AsmEvent):
invoke CoInitializeEx, 0,COINIT_APARTMENTTHREADED ;COINIT_MULTITHREADED
My  method QueryInterface receives rIId_ofeventclass  place IID_IMarshal spam, and then everything goes correctly
I will see other type like LocalServer32 (exe) like vb example
Title: Re: COM Events
Post by: Zen on April 21, 2015, 06:12:11 AM
MABDELOUAHAB,
The CodeProject has a large number of articles about COM programming: COM / COM+ (http://www.codeproject.com/KB/COM/)
Here is the section for: COM/DCOM/COM+ - Beginners  (http://www.codeproject.com/KB/COM/#Beginners)
These articles are excellent:
Introduction to COM - What It Is and How to Use It (http://www.codeproject.com/Articles/633/Introduction-to-COM-What-It-Is-and-How-to-Use-It)
Introduction to COM Part II - Behind the Scenes of a COM Server (http://www.codeproject.com/Articles/901/Introduction-to-COM-Part-II-Behind-the-Scenes-of-a)
The COM Macro-Architecture Topology (http://www.codeproject.com/Articles/1268/The-COM-Macro-Architecture-Topology)
COM Macro Architecture Topology - Servers (http://www.codeproject.com/Articles/1267/COM-Macro-Architecture-Topology-Servers)
COM Macro Architecture Topology - Clients (http://www.codeproject.com/Articles/1266/COM-Macro-Architecture-Topology-Clients)
COM IDs & Registry Keys in a Nutshell (http://www.codeproject.com/Articles/1265/COM-IDs-Registry-keys-in-a-nutshell)

There is also a whole series of articles (for C language programmers) by Jeff Glatt:
COM in Plain C (http://www.codeproject.com/Articles/13601/COM-in-plain-C)
COM in Plain C, Part Two (http://www.codeproject.com/Articles/13862/COM-in-plain-C-Part)
COM in Plain C, Part Three (http://www.codeproject.com/Articles/14037/COM-in-plain-C-Part)
COM in Plain C, Part Four (http://www.codeproject.com/Articles/14117/COM-in-plain-C-Part)
COM in Plain C, Part Five (http://www.codeproject.com/Articles/14183/COM-in-plain-C-Part)
COM in Plain C, Part Six (http://www.codeproject.com/Articles/14905/COM-in-plain-C-Part)
COM in Plain C, Part Seven (http://www.codeproject.com/Articles/15037/COM-in-plain-C-Part)
COM in Plain C, Part Eight (http://www.codeproject.com/Articles/17038/COM-in-plain-C-part)

...There are also a number of articles about using COM in ActiveX components, Visual Basic wrappers, connection points, and all kinds of other useful stuff,...
For instance: COM Connection Points (http://www.codeproject.com/Articles/3541/COM-Connection-Points). and, ActiveX EXE Wrappers (http://www.codeproject.com/Articles/16499/ActiveX-EXE-Wrappers)

...And,...if you are serious about COM programming,...there is no better reference than: Essential COM, Don Box (http://books.google.com/books/about/Essential_COM.html?id=kfRWvKSePmAC)

(http://books.google.com/books/content?id=kfRWvKSePmAC&printsec=frontcover&img=1&zoom=1&edge=curl&imgtk=AFLRE71Sd_1lGwgjtHIkd69UZyM-QeaXb-WDWWXUnPB3CRmTf3AHc1jMgWRZS438gyqKB7QmLtCQ9SlDOP3YjYU8a4zNodlhq0d1Yd7pZgHgaulBirP4ycHlLnhVwPY-kA8eAxKdC2FB)
Title: Re: COM Events
Post by: adeyblue on April 23, 2015, 02:28:26 AM
Oh yeah, I had changed it to ApartmentThreaded. Must've forgotten I did that before I started adding printfs and stuff to the other code.
Title: Re: COM Events
Post by: Zen on April 23, 2015, 05:06:15 AM
MABDELOUAHAB,
Here is an internet archive (the Wayback machine) of Japheth's Site: Japheth's Site, COM & Assembly (http://web.archive.org/web/20141003032346/http://www.japheth.de/)
...Scroll down the left side Menu to Miscellaneous, COM & Assembly,...
All his original MASM COM Source Code examples are located there and downloadable,...
Title: Re: COM Events
Post by: mabdelouahab on April 23, 2015, 05:15:53 AM
I have found some answers, but I'm trying scattered work Like (http://stackoverflow.com/questions/7477511/how-to-implement-imarshal-for-custom-marshalling-interface-from-out-of-proc-serv)
QuoteThe question is a bit not specific, so the answer will outline the main steps taking place.

Given is an interface pointer on the server side and the pointer needs to get marshaled into foreign apartment. The server COM object implements custom marshaler supposed to be picked up. The client expects the interface pointer to a proxy obtained through custom marshaling.

Server Side

COM queries the COM object in question for IMarshal interface - this succeeds, our object indeed implements it
COM calls IMarshal::GetUnmarshalClass to get CLSID of the class responsible for unmarshaling on client side; this might be the same CLSID of the server object , this could be proxy class CLSID, or proxy factory class CLSID - the idea is that COM requests this via method call, so object is free to return whatever seems appropriate
COM might call IMarshal::GetMarshalSizeMax to prepare a buffer for marshaling data
COM calls IMarshal::MarshalInterface to marhsal the data
Client Side

COM starts here getting eventually external request suggesting that some magic is necessary to spawn a proxy object and obtain COM interface pointer to be given to the controlling/caller application
COM has on hands CLSID of the unmarshaler class and data from the marshaler
COM instantiates a class using the CLSID
COM calls IMarhsal::UnmarshalInterface on the created class and provides IID it eventually wants to obtain
Note that on the last step above COM has the following:
or
QuoteNow back to original question, what is marshaling doing here at all? You are initializing an MTA thread and you are creating apartment threaded COM object CLSID_UserNotification there. COM creates the notification API in a side STA thread for you and then it tries to pass your callback there to match threading. It has to ask your COM object whether it does marshaling itself, or it needs this thing thing to be supplied. Your object has to say it does not marshal itself and it has no idea about it. This is what is going on. Make it COINIT_APARTMENTTHREADED and you will see a different picture.
I've added the IMarshal concluded that
When I called for Advice: QueryInterface receives iid_IMarshal
I resend the IMarshal Instance

Then automatically calls the IMarshal.GetUnmarshalClass, then   IMarshal.GetMarshalSizeMax After all this, the program stops
Quote
CreateClass OK
CreateInterface
QueryInterface IConnectionPointContainer OK
FindConnectionPoint OK
QueryInterface   iidClass  :
   <000000003,00000h,00000h<0C0h,000h,000h,000h,000h,000h,000h,046h>>QIf5
IMarshal@GetMarshalSizeMax iidClass:
     <000000000,00000h,00000h<0C0h,000h,000h,000h,000h,000h,000h,046h>>

    CoGetStandardMarshal  OK
     IMarshal.GetMarshalSizeMax pSize= 258
IMarshal@Release
QueryInterface   iidClass  :
   <0ECC8691B,0C1DBh,04DC0h<085h,05Eh,065h,0F6h,0C5h,051h,0AFh,049h>>
QueryInterface   iidClass  :
   <000000003,00000h,00000h<0C0h,000h,000h,000h,000h,000h,000h,046h>>QIf5
IMarshal@GetUnmarshalClass   iidClass  :
   <000000000,00000h,00000h<0C0h,000h,000h,000h,000h,000h,000h,046h>>
IMarshal@GetMarshalSizeMax iidClass:
     <000000000,00000h,00000h<0C0h,000h,000h,000h,000h,000h,000h,046h>>

    CoGetStandardMarshal  OK
     IMarshal.GetMarshalSizeMax pSize= 258
Title: Re: COM Events
Post by: mabdelouahab on April 23, 2015, 05:22:45 AM
    QueryInterface proc    lpME:dword ,riid:DWORD,ppvObj:DWORD
    LOCAL ff
        invoke crt_wprintf,cfm$("\n QueryInterface   iidClass  :\n   ")
        invoke PrintGUID,riid
        .if rv(IsEqualGUID,addr IID_IUnknown ,riid)
        invoke crt_wprintf,cfm$("_QIf2")
        mov eax,lpME
    mov ecx,ppvObj
    mov dword ptr [ecx],eax
    mov eax,S_OK
    jmp exQI
        .endif
        .if  rv(IsEqualGUID,addr IID_IDispatch,riid)
        invoke crt_wprintf,cfm$("_QIf3")
        mov eax,lpME
    mov ecx,ppvObj
    mov dword ptr [ecx],eax
    mov eax,S_OK
    jmp exQI
        .endif
        .if  rv(IsEqualGUID,addr IID___Class1,riid)
        invoke crt_wprintf,cfm$("_QIf4")
        mov eax,lpME
    mov ecx,ppvObj
    mov dword ptr [ecx],eax
    mov eax,S_OK
    jmp exQI
        .endif
        .if  rv(IsEqualGUID,addr IID_IMarshal,riid)
        invoke crt_wprintf,cfm$("QIf5")
        .if !Inst_InterfaceIMarshal
        mov ecx,rv(CreateInterface@IMarshal)
        mov Inst_InterfaceIMarshal,ecx
        .endif
        lea eax,Inst_InterfaceIMarshal
    mov ecx,ppvObj
    mov [ecx],eax
    mov eax,S_OK
    jmp exQI
        .endif
;         .if  rv(IsEqualGUID,addr IID_INoMarshal,riid)
;         invoke crt_wprintf,cfm$("QIf7")
;         lea eax,Inst_ICF ; IClassFactory
;     mov ecx,ppvObj
;     mov dword ptr [ecx],eax
;     mov eax,S_OK
;     jmp exQI
;         .endif
        mov eax,E_NOINTERFACE
    exQI:
    ret
    QueryInterface endp

IMarshal_QIP typedef proto IMarshal_QIP :DWORD,:DWORD,:DWORD
IMarshal_QRP typedef proto IMarshal_QRP :DWORD
IMarshal_RLP typedef proto IMarshal_RLP :DWORD

IMarshal_GetUnmarshalClassProto typedef proto IMarshal_GetUnmarshalClassProto :DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD
IMarshal_GetMarshalSizeMaxProto typedef proto IMarshal_GetMarshalSizeMaxProto :DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD
IMarshal_MarshalInterfaceProto typedef proto IMarshal_MarshalInterfaceProto :DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD
IMarshal_UnmarshalInterfaceProto typedef proto IMarshal_UnmarshalInterfaceProto :DWORD,:DWORD,:DWORD,:DWORD
IMarshal_ReleaseMarshalDataProto typedef proto IMarshal_ReleaseMarshalDataProto :DWORD,:DWORD
IMarshal_DisconnectObjectProto typedef proto IMarshal_DisconnectObjectProto :DWORD,:DWORD

IMarshal_QIPP typedef ptr  IMarshal_QIP 
IMarshal_QRPP typedef ptr  IMarshal_QRP 
IMarshal_RLPP typedef ptr  IMarshal_RLP 
IMarshal_GetUnmarshalClassVal typedef ptr IMarshal_GetUnmarshalClassProto
IMarshal_GetMarshalSizeMaxVal typedef ptr IMarshal_GetMarshalSizeMaxProto
IMarshal_MarshalInterfaceVal typedef ptr IMarshal_MarshalInterfaceProto
IMarshal_UnmarshalInterfaceVal typedef ptr IMarshal_UnmarshalInterfaceProto
IMarshal_ReleaseMarshalDataVal typedef ptr IMarshal_ReleaseMarshalDataProto
IMarshal_DisconnectObjectVal typedef ptr IMarshal_DisconnectObjectProto

IMarshal            STRUCT
    QueryInterface IMarshal_QIPP 0
    AddRef IMarshal_QRPP 0
    Release IMarshal_RLPP 0
GetUnmarshalClass    IMarshal_GetUnmarshalClassVal 0
GetMarshalSizeMax    IMarshal_GetMarshalSizeMaxVal 0
MarshalInterface IMarshal_MarshalInterfaceVal 0
UnmarshalInterface    IMarshal_UnmarshalInterfaceVal 0
ReleaseMarshalData    IMarshal_ReleaseMarshalDataVal 0
DisconnectObject    IMarshal_DisconnectObjectVal 0
IMarshal            ENDS
.data

pMarshal dd 0

.code
    IMarshal@QueryInterface proc    lpME:dword ,riid:DWORD,ppvObj:DWORD
        invoke crt_wprintf,cfm$("\n ICP_QIf")
        invoke PrintGUID,riid
        mov eax,lpME
    mov ecx,ppvObj
    mov dword ptr [ecx],eax
    mov eax,S_OK
    ret
    IMarshal@QueryInterface endp

IMarshal@AddRef proc lpME:dword
invoke crt_wprintf,cfm$("\n IMarshal@AddRef ")
inc RefCount
mov eax,RefCount
ret
IMarshal@AddRef endp
IMarshal@Release proc lpME:dword
invoke crt_wprintf,cfm$("\n IMarshal@Release")
dec RefCount
mov eax,RefCount
ret
IMarshal@Release endp
IMarshal@GetUnmarshalClass proc lpME :DWORD,riid:DWORD,pv:DWORD,dwDestContext:DWORD,pvDestContext:DWORD,mshlflags:DWORD,pClsid:DWORD
LOCAL dwRegister
LOCAL dd__
;jmp stest2
        lea eax,pclsismarsh
    mov ecx,pClsid
    m2m dword ptr [ecx],dword ptr [eax]
    m2m dword ptr [ecx+4],dword ptr [eax+4]
    m2m dword ptr [ecx+8],dword ptr [eax+8]
    m2m dword ptr [ecx+12],dword ptr [eax+12]
    invoke crt_wprintf,cfm$("\n IMarshal@GetUnmarshalClass   iidClass  :\n   ")
invoke PrintGUID,riid
jmp IMarshal@GetUnmarshalClassexit
;************************************************************** 1 test
stest2:
mov pMarshal,0
        invoke CoGetStandardMarshal,addr IID___Class1,NULL, dwDestContext,pvDestContext, mshlflags,addr pMarshal
        .if pMarshal
        invoke crt_wprintf,cfm$("\n    CoGetStandardMarshal OK ")
mov ecx,pMarshal
mov edx,ecx
mov ecx,[ecx]
invoke [ECX].IMarshal.GetUnmarshalClass,edx,addr IID___Class1, NULL, dwDestContext, pvDestContext, mshlflags, pClsid
.if !eax
invoke crt_wprintf,cfm$("\n     GetUnmarshalClass OK ")
.endif
mov ecx,pMarshal
mov edx,ecx
mov ecx,[ecx]
invoke [ECX].IMarshal.Release,edx
.else
invoke crt_wprintf,cfm$("\n CoGetStandardMarshal ___________ Fail ")       
        .endif
IMarshal@GetUnmarshalClassexit:
ret
IMarshal@GetUnmarshalClass endp
.data
h dd 0
m_spIStream dd 0
cbMax dq 0
        iLNull  dq  0
        uLLen  dq  0
        spIPersistStm dd 0
.code

IMarshal@GetMarshalSizeMax proc lpME:DWORD,riid:DWORD,pv:DWORD,dwDestContext:DWORD,pvDestContext:DWORD,mshlflags:DWORD,pSize:DWORD
LOCAL lff
local ulSize,hGlobal,ppStreamReceiver_
mov lff,0
invoke crt_wprintf,cfm$("\n IMarshal@GetMarshalSizeMax iidClass: \n     ")
invoke PrintGUID,riid
invoke crt_wprintf,cfm$("\n")
        invoke CoGetStandardMarshal,addr IID___Class1,NULL, dwDestContext,pvDestContext, mshlflags,addr pMarshal
        .if pMarshal
        invoke crt_wprintf,cfm$("\n    CoGetStandardMarshal  OK ")
mov ecx,pMarshal
mov edx,ecx
mov ecx,[ecx]
invoke [ECX].IMarshal.GetMarshalSizeMax,edx,addr IID___Class1, pv, dwDestContext, pvDestContext, mshlflags, pSize
.if !eax
mov eax,pSize
mov edx,[eax]
invoke crt_wprintf,cfm$("\n     IMarshal.GetMarshalSizeMax pSize= %d "),edx
.endif
.else
invoke crt_wprintf,cfm$("\n    CoGetStandardMarshal  Fail ")       
        .endif
IMarshal@GetMarshalSizeMaxexit:
mov eax,S_OK ;E_FAIL
ret
IMarshal@GetMarshalSizeMax endp
IMarshal@MarshalInterface proc  lpME:DWORD,pStm:DWORD,riid:DWORD,pv:DWORD,dwDestContext:DWORD,pvDestContext:DWORD,mshlflags:DWORD


invoke crt_wprintf,cfm$("\n\n IMarshal@MarshalInterface ")
ret
IMarshal@MarshalInterface endp
IMarshal@UnmarshalInterface proc  lpME:DWORD,pStm:DWORD,riid:DWORD,ppv:DWORD

invoke crt_wprintf,cfm$("\n IMarshal@UnmarshalInterface")
mov eax,E_NOTIMPL
ret
IMarshal@UnmarshalInterface endp

IMarshal@ReleaseMarshalData proc lpME:dword ,pStm:DWORD
invoke crt_wprintf,cfm$("\n\n IMarshal@ReleaseMarshalData ")
ret
IMarshal@ReleaseMarshalData endp
IMarshal@DisconnectObject proc lpME:dword ,dwReserved:DWORD
invoke crt_wprintf,cfm$("\n\n IMarshal@DisconnectObject")
ret
IMarshal@DisconnectObject endp

CreateInterface@IMarshal proc
invoke LocalAlloc,LMEM_FIXED or LMEM_ZEROINIT ,sizeof IMarshal
mov edi,eax
mov dword ptr [edi] ,OFFSET IMarshal@QueryInterface
add edi,4
mov dword ptr [edi] ,OFFSET IMarshal@AddRef
add edi,4
mov dword ptr [edi] ,OFFSET IMarshal@Release
add edi,4
mov dword ptr [edi] ,OFFSET IMarshal@GetUnmarshalClass
add edi,4
mov dword ptr [edi] ,OFFSET IMarshal@GetMarshalSizeMax
add edi,4
mov dword ptr [edi] ,OFFSET IMarshal@MarshalInterface
add edi,4
mov dword ptr [edi] ,OFFSET IMarshal@UnmarshalInterface
add edi,4
mov dword ptr [edi] ,OFFSET IMarshal@ReleaseMarshalData
add edi,4
mov dword ptr [edi] ,OFFSET IMarshal@DisconnectObject
ret
CreateInterface@IMarshal endp

Title: Re: COM Events
Post by: mabdelouahab on April 23, 2015, 05:27:07 AM
For illustration
I added to the QueryInterface:

        .if  rv(IsEqualGUID,addr IID_IMarshal,riid)
        invoke crt_wprintf,cfm$("QIf5")
        .if !Inst_InterfaceIMarshal
        mov ecx,rv(CreateInterface@IMarshal)
        mov Inst_InterfaceIMarshal,ecx
        .endif
        lea eax,Inst_InterfaceIMarshal
    mov ecx,ppvObj
    mov [ecx],eax
    mov eax,S_OK
    jmp exQI
        .endif

With the addition of IMarshal inc
Title: Re: COM Events
Post by: Zen on April 23, 2015, 05:42:17 AM
MABDELOUAHAB,
Can you post your current source (and maybe a compiled executable) for your client ???
...So, that we can understand what you've got that actually WORKS ???
Title: Re: COM Events
Post by: mabdelouahab on April 23, 2015, 06:36:55 AM
OK Zen
dont forget \vbexmple\REG.bat
Title: Re: COM Events
Post by: Gunther on April 23, 2015, 07:03:10 AM
Hi mabdelouahab,

is a VB installation necessary for your example?

Gunther
Title: Re: COM Events
Post by: mabdelouahab on April 23, 2015, 07:39:21 AM
I Add masm server example, Choose which Server you want to , and If you choose masm server , run "\AsmEvent\REG.bat"
Title: Re: COM Events
Post by: Gunther on April 24, 2015, 02:07:37 AM
That's fine. Thank you.

Gunther
Title: Re: COM Events
Post by: Zen on April 24, 2015, 06:33:20 AM
MABDELOUAHAB,
I was looking at your server code (which presumably compiles into AsmEvent.dll, located in the AsmEvent directory), including the DEF file:
; MyCom2.def : Declares the module parameters.

LIBRARY      "AsmEvent.DLL"

EXPORTS
DllCanUnloadNow        @1 PRIVATE
DllGetClassObject      @2 PRIVATE
DllRegisterServer      @3 PRIVATE
DllUnregisterServer    @4 PRIVATE



I ran the DUMPBIN utility on the AsmEvent DLL with the /EXPORTS option, and, yes, it told me that AsmEvent.dll does export  DllGetClassObject (also, DllRegisterServer, DllUnregisterServer, and DllCanUnloadNow). I'm assuming that AsmEvent.dll is an In-Proc server, because it's a DLL (In-Proc servers must be DLLs). But, without the implementation of DllRegisterServer, I can't be sure.

...Anyway, I couldn't find the implementation of these exported functions.
If DLL doesn't export DllGetClassObject, all activation calls will fail.

This quote is from: The Rules of the Component Object Model, MSDN (https://msdn.microsoft.com/en-us/library/ms810016.aspx)
QuoteServer Rules
In-process servers must export DllGetClassObject and DllCanUnloadNow.
In-process servers must support COM self-registration.
In-process and local servers should put an OLESelfReg string in their file version information.
In-process servers should export DllRegisterServer and DllUnRegisterServer.
Local servers should support the /RegServer and /UnRegServer command-line switches.

This quote is from: Introduction to COM Part II - Behind the Scenes of a COM Server (http://www.codeproject.com/Articles/901/Introduction-to-COM-Part-II-Behind-the-Scenes-of-a)

Quote from: Introduction to COM Part II - Behind the Scenes of a COM ServerAn in-proc server must meet two criteria before it can be used by the COM library:
It must be registered properly under the HKEY_CLASSES_ROOT\CLSID key.
It must export a function called DllGetClassObject().

Here is a good description of: How Does COM Activation Work Anyway?, Larry Osterman's Blog (http://blogs.msdn.com/b/larryosterman/archive/2004/10/12/241420.aspx) (The article's hyperlinks are dead, but, you can Google them.)

DllGetClassObject Entry Point, MSDN (https://msdn.microsoft.com/en-us/library/ms680760(v=vs.85).aspx)

Create Class (which is in the client code directory, TestEvents.inc, looks like this)
CreateClass Proc

    invoke CoCreateInstance,addr sCLSID_Class1,NULL,CLSCTX_LOCAL_SERVER,addr IID_IUnknown,addr Inst_IUnknown
        .if eax == S_OK
LEA ECX, Inst_Class1
PUSH ECX
lea eax ,IID__Class1
        PUSH EAX
        MOV EDX,Inst_IUnknown
        PUSH EDX
        MOV EDX,[EDX]
        CALL DWORD PTR [EDX]
.if !eax
        invoke crt_wprintf,cfm$("\n CreateClass OK ")
            MOV EAX,TRUE
.else
        invoke crt_wprintf,cfm$("\n CreateClass fail ")
            MOV EAX,FALSE
.endif
        .else
        MOV EAX,FALSE
        .endif
ret
CreateClass endp


This routine is called in TestEvent.asm. Presumably, TestEvent.asm will be compiled into the client exe.
You know, it's confusing,...all these directories have files with the same names (yes, I know, the paths are different).
Title: Re: COM Events
Post by: Zen on April 25, 2015, 03:29:30 AM
MABDELOUAHAB,
You will notice in the above call to CoCreateInstance (https://msdn.microsoft.com/en-us/library/windows/desktop/ms686615(v=vs.85).aspx), that the CLSCTX_LOCAL_SERVER member of the CLSCTX Enumeration (https://msdn.microsoft.com/en-us/library/windows/desktop/ms693716(v=vs.85).aspx) is specified, indicating that the server is: an Out-Of-Process Server (The EXE code that creates and manages objects of this class runs on same machine but is loaded in a separate process space.)

The following is from: COM Clients and Servers, MSDN (https://msdn.microsoft.com/en-us/library/windows/desktop/ms683835(v=vs.85).aspx)
QuoteThere are two main types of servers, in-process and out-of-process. In-process servers are implemented in a dynamic linked library (DLL), and out-of-process servers are implemented in an executable file (EXE). Out-of-process servers can reside either on the local computer or on a remote computer.

Informative reading: COM Server Responsibilities, MSDN (https://msdn.microsoft.com/en-us/library/windows/desktop/ms690101(v=vs.85).aspx)

...So,...what is it ??? An In-Proc Server or an Out-Of-Process Server ??? I think that neglecting these kinds of critically important details in your current project, is why MASM Forum members are reluctant to provide suggestions and help for your 'problem',...
If you don't know, just ask,...there a number of extremely-knowledgeable, World-Class COM programmers that belong to this Forum,...
...Heck,...even DAVE knows quite a bit about COM,...:icon_eek:

...Here's how Japheth implements DllGetClassObject (from, SimpleServer.asm, in the zip file, Simple Server Example, Japheth.zip (http://masm32.com/board/index.php?topic=4153.msg44120#msg44120)):
;--------------------------------------------------------------
;--- DllGetClassObject: scans object table to see if requested
;--- CLSID is in there. If yes, creates an IClassFactory object
;--------------------------------------------------------------

DllGetClassObject PROC public uses esi rclsid:ptr CLSID,riid:ptr IID,ppReturn:ptr LPCLASSFACTORY

mov eax, ppReturn
mov DWORD PTR [eax], 0

mov esi, offset ObjectMap
mov ecx, OBJECTMAPITEMS
.while (ecx)
push ecx
invoke IsEqualGUID, rclsid, [esi].ObjectEntry.pClsId
pop ecx
.break .if (eax)
add esi, sizeof ObjectEntry
dec ecx
.endw
.if (!ecx)
mov eax, CLASS_E_CLASSNOTAVAILABLE
jmp done
.endif

invoke Create@CClassFactory, esi
.if (eax == NULL)
mov eax, E_OUTOFMEMORY
jmp done
.endif
mov esi,eax

invoke vf(esi,IClassFactory,QueryInterface),riid,ppReturn
push eax
invoke vf(esi,IClassFactory,Release)
pop eax
done:
ret

DllGetClassObject ENDP


...That file also has example implementations of: DllRegisterServer, DllUnregisterServer, and, DllCanUnloadNow.

...Here are some interesting blog articles from Raymond Chen:
How Can I Tell Whether a DLL Has Been Registered? (http://blogs.msdn.com/b/oldnewthing/archive/2011/11/10/10235540.aspx)
Registration-Free COM the Old-Fashioned Way (http://blogs.msdn.com/b/oldnewthing/archive/2012/04/06/10291324.aspx)

...And, you should probably read these too (from Larry Osterman's Blog):
So What Exactly IS COM Anyway ?, Larry Osterman (http://blogs.msdn.com/b/larryosterman/archive/2004/10/15/242989.aspx)
Minimal COM Object Registration, Larry Osterman (http://blogs.msdn.com/b/larryosterman/archive/2006/01/05/509731.aspx)
What Registry Entries Are Needed To Register a COM Object ?, Larry Osterman (http://blogs.msdn.com/b/larryosterman/archive/2006/01/11/511647.aspx)
COM Registration If You Need a Typelib, Larry Osterman (http://blogs.msdn.com/b/larryosterman/archive/2006/01/09/510856.aspx)
What Are These "Threading Models" and Why Do I Care?, Larry Osterman (http://blogs.msdn.com/b/larryosterman/archive/2004/04/28/122240.aspx)
COM Registration for Cross Process Access, Larry Osterman (http://blogs.msdn.com/b/larryosterman/archive/2006/01/06/510168.aspx)
When Do You Need an APPID in your COM Registration ?, Larry Osterman (http://blogs.msdn.com/b/larryosterman/archive/2006/01/04/509436.aspx)

...OK,...sorry,...that last section is just overkill,...
Title: Re: COM Events
Post by: mabdelouahab on April 25, 2015, 05:53:14 AM
Hi Zen
I thank you for helping me,
Just for clarification, I found that information available, clear, but there is always an error.
I focused on errors only, in order to know the real problem
Before speaking to the real problem, I want to point out what I have learned
When the Client forwards request to the server to associate a connection point, The server sends the request to the proxy, either iid of custom interface or iid_IMarshal ,
* iid of custom interface In the case of single Thread,
* IID_IMarshal In the case of Multi-Thread,In this case the system intervenes by COMBASE.DLL to solve the problem between disputants
The Client must send our Instance of IMarshal, then COM sends 3 consecutive requests
1.IMarshal::GetUnmarshalClass is called to obtain the CLSID of the proxy object.
2.IMarshal::GetMarshalSizeMax is called to determine the size of the marshaling packet that the interface needs.
The system allocates the memory and then creates a stream object that wraps the memory buffer.
3.IMarshal::MarshalInterface is called to tell the object to marshal the interface pointer into the stream.

Here detailing locations Will That Be Custom or Standard Marshaling? (http://thrysoee.dk/InsideCOM+/ch14c.htm) or How to marshal interfaces across apartments in Visual C++ (https://support.microsoft.com/en-us/kb/206076)(for more information)
I go back to my problem
I used VS2012 Debuger to access error, I discovered that ...(Focused with me please)
Error in which debt program stops Is that the Parametre sent to the function overlap, Sometimes at the programme ، and Sometimes at the COMBASE.DLL


(https://googledrive.com/host/0B5q3H3sB5u6QQ0JBeWt2dGhjRXc)
this is mov edx,pSize
mov dword ptr [edx],255

In
IMarshal@GetMarshalSizeMax   proc     lpME:DWORD, riid:DWORD,pv:DWORD,dwDestContext:DWORD,pvDestContext:DWORD,mshlflags:DWORD,pSize:DWORD
The procedure receives the value of pSize 0

(https://googledrive.com/host/0B5q3H3sB5u6QVFdvSTYtc1hUNFE)
this is IStream::Write
but pStream = addr of IID_INoMarshal
I think that the Align
Title: Re: COM Events
Post by: mabdelouahab on April 25, 2015, 07:51:39 AM
I've translated the proceedings being conducted by the COMBASE.DLL in the BackGround:
PMarshal proc pUnknown,riid,  dwDestContext, pvDestContext, dwFlags

; AddRef the incoming pointer to verify that it is safe.
;******************* pUnknown::AddRef
        MOV EDX, pUnknown
        PUSH EDX   
        MOV EDX,[EDX]   
        CALL DWORD PTR [EDX+4] ; pUnknown::AddRef

; Do you support custom marshaling?
;******************* pUnknown::QueryInterface
        PUSH OFFSET pMarshal_   
        PUSH OFFSET IID_IMarshal   
        MOV EDX, pUnknown
        PUSH EDX   
        MOV EDX,[EDX]   
        CALL DWORD PTR [EDX] ; pUnknown::QueryInterface
; I guess not, so we'll use standard marshaling.
.if eax == E_NOINTERFACE
invoke CoGetStandardMarshal,riid, pUnknown, dwDestContext, pvDestContext, dwFlags, addr pMarshal_
.endif
; OK, what's the CLSID of your proxy?
mov ecx,pMarshal_
mov edx,ecx
mov ecx,[ecx]
invoke [ECX].IMarshal.GetUnmarshalClass,edx,riid, pUnknown, dwDestContext, pvDestContext, dwFlags,addr clsid
; How much space do you need?
mov ecx,pMarshal_
mov edx,ecx
mov ecx,[ecx]
invoke [ECX].IMarshal.GetMarshalSizeMax,edx,riid, pUnknown, dwDestContext, pvDestContext, dwFlags,addr packetSize
; Allocate that memory.
mov ecx,packetSize
add ecx,sizeof CLSID
mov pMem ,rv(GlobalAlloc,GHND, ecx );
; Turn it into a stream object.
invoke CreateStreamOnHGlobal,pMem, FALSE, addr pStream_
.if !eax
invoke crt_wprintf,cfm$("\n .... CreateStreamOnHGlobal OK \n")
.endif
; Write the CLSID of the proxy into the stream.
invoke WriteClassStm,pStream_,addr clsid
.if !eax
invoke crt_wprintf,cfm$("\n .... WriteClassStm OK \n")
.endif
; Marshal that interface into the stream.
mov ecx,pMarshal_
mov edx,ecx
mov ecx,[ecx]
invoke [ECX].IMarshal.MarshalInterface,edx,pStream_,riid, pUnknown, dwDestContext, pvDestContext, dwFlags

push eax

; Release everything in sight.
        MOV EDX, pStream_
        PUSH EDX   
        MOV EDX,[EDX]   
        CALL DWORD PTR [EDX+8] ; pStream::Release

        MOV EDX, pMarshal_
        PUSH EDX   
        MOV EDX,[EDX]   
        CALL DWORD PTR [EDX+8] ; pMarshal::Release

        MOV EDX, pUnknown
        PUSH EDX   
        MOV EDX,[EDX]   
        CALL DWORD PTR [EDX+8] ; pUnknown::Release

pop eax

ret
PMarshal endp
Title: Re: COM Events
Post by: mabdelouahab on April 25, 2015, 08:06:59 AM
Without the use of any communication with the server
And without any new CoCreateInstanceof objects
When you create new interface and use CoMarshalInterface the com is the same with you and produce the same errors

invoke CoInitializeEx, NULL,COINIT_MULTITHREADED    ;COINIT_APARTMENTTHREADED ;
invoke CoCreateGuid,addr pclsismarsh
mov Inst_InterfaceMASM,rv(CreateInterfaceMASM)
mov Inst_ICF,rv(CreateInterface@IClassFactory)
invoke CoRegisterClassObject,addr pclsismarsh,addr  Inst_ICF ,CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE,addr dwReg__
  invoke GlobalAlloc,GMEM_MOVEABLE,ecx
  mov hGlobal,eax
  invoke  CreateStreamOnHGlobal, hGlobal, TRUE,addr ppStreamReceiver_
  invoke CoMarshalInterface ,ppStreamReceiver_, addr IID___Class1, addr Inst_Interface, MSHCTX_LOCAL, NULL, MSHLFLAGS_NORMAL
Title: Re: COM Events
Post by: mabdelouahab on April 25, 2015, 08:38:32 PM
Quote from: Zen on April 24, 2015, 06:33:20 AM
MABDELOUAHAB,
I was looking at your server code (which presumably compiles into AsmEvent.dll, located in the AsmEvent directory), including the DEF file:
; MyCom2.def : Declares the module parameters.

LIBRARY      "AsmEvent.DLL"

EXPORTS
DllCanUnloadNow        @1 PRIVATE
DllGetClassObject      @2 PRIVATE
DllRegisterServer      @3 PRIVATE
DllUnregisterServer    @4 PRIVATE



I ran the DUMPBIN utility on the AsmEvent DLL with the /EXPORTS option, and, yes, it told me that AsmEvent.dll does export  DllGetClassObject (also, DllRegisterServer, DllUnregisterServer, and DllCanUnloadNow). I'm assuming that AsmEvent.dll is an In-Proc server, because it's a DLL (In-Proc servers must be DLLs). But, without the implementation of DllRegisterServer, I can't be sure.
....
Not important, because CoCreateInstanceEx locate COM component DLL (From registry) then load it into memory using LoadLibrary, then locate DllGetClassObject function exported from the DLL using GetProcAddress Win32 API, Call DllGetClassObject and obtain IClassFactory interface of your component class factory
Title: Re: COM Events
Post by: mabdelouahab on April 25, 2015, 08:52:13 PM
Quote from: Zen on April 25, 2015, 03:29:30 AM
MABDELOUAHAB,
You will notice in the above call to CoCreateInstance (https://msdn.microsoft.com/en-us/library/windows/desktop/ms686615(v=vs.85).aspx), that the CLSCTX_LOCAL_SERVER member of the CLSCTX Enumeration (https://msdn.microsoft.com/en-us/library/windows/desktop/ms693716(v=vs.85).aspx) is specified, indicating that the server is: an Out-Of-Process Server (The EXE code that creates and manages objects of this class runs on same machine but is loaded in a separate process space.)

The following is from: COM Clients and Servers, MSDN (https://msdn.microsoft.com/en-us/library/windows/desktop/ms683835(v=vs.85).aspx)
QuoteThere are two main types of servers, in-process and out-of-process. In-process servers are implemented in a dynamic linked library (DLL), and out-of-process servers are implemented in an executable file (EXE). Out-of-process servers can reside either on the local computer or on a remote computer.

Informative reading: COM Server Responsibilities, MSDN (https://msdn.microsoft.com/en-us/library/windows/desktop/ms690101(v=vs.85).aspx)

...So,...what is it ??? An In-Proc Server or an Out-Of-Process Server ??? I think that neglecting these kinds of critically important details in your current project ...
Zen
I haven't neglected this, and explained that if case single Thread the QueryInterface will receive IID of EventClass, and in the case of multiple thread
The QueryInterface  receives IID_IMarshal Because the program required that Marshal our Interface to send it
And Excuse me for my english
Title: Re: COM Events
Post by: mabdelouahab on April 25, 2015, 09:08:53 PM
Quote from: Zen on April 25, 2015, 03:29:30 AM
..., is why MASM Forum members are reluctant to provide suggestions and help for your 'problem',...
If you don't know, just ask,...there a number of extremely-knowledgeable, World-Class COM programmers that belong to this Forum,...
...Heck,...even DAVE knows quite a bit about COM,...

Always I'm getting help from Forum members, Thank everyone of course  :biggrin:
If someone can continue with me, I suggested that I restored from zero, and does not add anything to the project until I explained
Title: Re: COM Events
Post by: mabdelouahab on April 25, 2015, 10:29:24 PM
First: I make the very simplest server software does not contain only 1 function and 1 event
Open VB New Project an Select DLL ActiveX , In Class1 add:

Public Event EventForTest()
Public Sub MethodForTest()
    MsgBox "Hi Is Me ..."       ' invoke MessageBox ...
    RaiseEvent EventForTest   ' FireEvents EventForTest   
End Sub

Rename Class1 to ClsForTest and rename Project1 to DllForTest
In FILE Menu select "Create DllForTest.DLL" and save it

VB will automatically made Active X Dll contains the following:_ClsForTest Dispatsh ;__ClsForTest (Event Dispatsh ) ; Inc file is as follows (Generate by me):
.data
CLSID_ClsForTest  GUID <0B6E21F7Ch,0AC81h,040EDh,<089h,0F7h,0D9h,034h,05Fh,027h,051h,066h>>
IID__ClsForTest    GUID <06B81DDC9h,0881Bh,0486Fh,<087h,08Bh,03Ch,0BCh,0A3h,005h,09Dh,090h>>

Inst__ClsForTest dd 0

_ClsForTest struct
    QueryInterface dd 0
    AddRef dd 0
    Release dd 0
    GetTypeInfoCount dd 0
    GetTypeInfo dd 0
    GetIDsOfNames dd 0
    _Invoke dd 0
MethodForTest dd 0
_ClsForTest ends

.code
_ClsForTest@Release proc
        MOV EDX, Inst__ClsForTest
        PUSH EDX   
        MOV EDX,[EDX]   
        CALL DWORD PTR [EDX+8] ;Call ClsForTest.Release
ret
_ClsForTest@Release endp
_ClsForTest@MethodForTest proc
        MOV EDX, Inst__ClsForTest
        PUSH EDX   
        MOV EDX,[EDX]   
        CALL DWORD PTR [EDX+28] ;Call ClsForTest.MethodForTest
ret
_ClsForTest@MethodForTest endp

_ClsForTest@CreateClass Proc
LOCAL __IUnknown
    invoke CoCreateInstance,addr CLSID_ClsForTest,NULL,CLSCTX_ALL,addr IID_IUnknown,addr __IUnknown
        .if eax == S_OK
LEA ECX, Inst__ClsForTest
PUSH ECX
lea eax ,IID__ClsForTest
        PUSH EAX
        MOV EDX,__IUnknown
        PUSH EDX
        MOV EDX,[EDX]
        CALL DWORD PTR [EDX] ;QueryInterface
.if !eax
        invoke crt_wprintf,cfm$("\n CreateClass _ClsForTest OK ")
            MOV EAX,TRUE
.else
        invoke crt_wprintf,cfm$("\n CreateClass _ClsForTest  fail ")
            MOV EAX,FALSE
.endif
        .else
        MOV EAX,FALSE
        .endif
ret
_ClsForTest@CreateClass endp

Go back to Masm, make the following
create New Consol :
__UNICODE__ equ 1
include \masm32\include\masm32rt.inc
.data
IID_IUnknown GUID <000000000H,00000H,00000H,<0C0H,000H,000H,000H,000H,000H,000H,046H>>

include Cls_ClsForTest.inc
.code
Start:
invoke CoInitializeEx, NULL,COINIT_MULTITHREADED    ;COINIT_APARTMENTTHREADED ;
.if rv( _ClsForTest@CreateClass); Create New ClsForTest
invoke _ClsForTest@MethodForTest ;ClsForTest.MethodForTest
invoke _ClsForTest@Release ; ClsForTest.Release
.endif
invoke CoUninitialize
exit
End Start

add the INC file of DllFor test to Proj, Must register DllForTest.dll "  REGSVR32 "DllForTest.dll"  "
Run and I will complete
Title: Re: COM Events
Post by: mabdelouahab on April 26, 2015, 12:57:32 AM
at here I work without EVENT
if I want to work with events we must create an interface at my application then advise it to the Server DLL

I generate Inc File for the Event Clss (__ClsForTest)  , add it to the project
.data

IID___ClsForTest  GUID <03D369F24h,0B1BFh,04816h,<0BEh,0A2h,0B1h,0AFh,0A2h,0FFh,098h,053h>>

Inst__ClsForTest dd 0
___ClsForTest@RefCount dd 0

__ClsForTest struct ;;;;;;;; Events
    QueryInterface dd 0
    AddRef dd 0
    Release dd 0
    GetTypeInfoCount dd 0
    GetTypeInfo dd 0
    GetIDsOfNames dd 0
    _Invoke dd 0
EventForTest dd 0
__ClsForTest ends

.code

    __ClsForTest@QueryInterface proc    lpME:dword ,riid:DWORD,ppvObj:DWORD
invoke crt_wprintf,cfm$("\n __ClsForTest@QueryInterface")
        .if rv(IsEqualGUID,addr IID_IUnknown ,riid)
        mov eax,lpME
    mov ecx,ppvObj
    mov dword ptr [ecx],eax
    mov eax,S_OK
    jmp __ClsForTest@QueryInterfaceExit
        .endif
        .if  rv(IsEqualGUID,addr IID___ClsForTest,riid)
        mov eax,lpME
    mov ecx,ppvObj
    mov dword ptr [ecx],eax
    mov eax,S_OK
    jmp __ClsForTest@QueryInterfaceExit
        .endif
        mov eax,E_NOINTERFACE
    __ClsForTest@QueryInterfaceExit:
    ret
    __ClsForTest@QueryInterface endp
__ClsForTest@AddRef proc lpME:dword
invoke crt_wprintf,cfm$("\n __ClsForTest@AddRef")
inc ___ClsForTest@RefCount
mov eax,___ClsForTest@RefCount
ret
__ClsForTest@AddRef endp
__ClsForTest@Release proc lpME:dword
invoke crt_wprintf,cfm$("\n __ClsForTest@Release")
dec ___ClsForTest@RefCount
mov eax,___ClsForTest@RefCount
ret
__ClsForTest@Release endp
__ClsForTest@GetTypeInfoCount proc lpME:dword ,pctinfo:DWORD
invoke crt_wprintf,cfm$("\n __ClsForTest@GetTypeInfoCount")
mov eax,E_NOTIMPL
ret
__ClsForTest@GetTypeInfoCount endp
__ClsForTest@GetTypeInfo proc lpME:dword ,itinfo:DWORD,lcid:DWORD,pptinfo:DWORD
invoke crt_wprintf,cfm$("\n __ClsForTest@GetTypeInfo")
mov eax,E_NOTIMPL
ret
__ClsForTest@GetTypeInfo endp
__ClsForTest@GetIDsOfNames proc lpME:dword ,riid:DWORD,rgszNames:DWORD,cNames:DWORD,lcid:DWORD,rgdispid:DWORD
invoke crt_wprintf,cfm$("\n __ClsForTest@GetIDsOfNames")
mov eax,E_NOTIMPL
ret
__ClsForTest@GetIDsOfNames endp
__ClsForTest@_Invoke proc lpME:dword ,dispidMember:SDWORD,riid:DWORD,lcid:DWORD,wFlags:WORD,pdispparams:DWORD,pvarResult:DWORD,pexcepinfo:DWORD,puArgErr:DWORD
invoke crt_wprintf,cfm$("\n __ClsForTest@_Invoke %d ") ,dispidMember
mov ecx,dispidMember
cmp ecx,1
jne @F
push lpME
call __ClsForTest@MethodForTest
jmp __ClsForTest@_InvokeExit
@@: ;cmp ecx,2
;jne @F
; push lpME
; call __ClsForTest@MethodForTest
; jmp __ClsForTest@_InvokeExit...............
__ClsForTest@_InvokeExit:
xor eax,eax
ret
__ClsForTest@_Invoke endp
__ClsForTest@MethodForTest proc lpME:dword
invoke crt_wprintf,cfm$("\n __ClsForTest@MethodForTest")
invoke MessageBox,0,chr$(" __ClsForTest@MethodForTest Event Fired OK"),0,0
ret
__ClsForTest@MethodForTest endp

__ClsForTest@CreateInterface proc
invoke LocalAlloc,LMEM_FIXED or LMEM_ZEROINIT ,sizeof __ClsForTest
mov edi,eax
mov dword ptr [edi] ,OFFSET __ClsForTest@QueryInterface
add edi,4
mov dword ptr [edi] ,OFFSET __ClsForTest@AddRef
add edi,4
mov dword ptr [edi] ,OFFSET __ClsForTest@Release
add edi,4
mov dword ptr [edi] ,OFFSET __ClsForTest@GetTypeInfoCount
add edi,4
mov dword ptr [edi] ,OFFSET __ClsForTest@GetTypeInfo
add edi,4
mov dword ptr [edi] ,OFFSET __ClsForTest@GetIDsOfNames
add edi,4
mov dword ptr [edi] ,OFFSET __ClsForTest@_Invoke
add edi,4
mov dword ptr [edi] ,OFFSET __ClsForTest@MethodForTest
ret
__ClsForTest@CreateInterface endp
__ClsForTest@Advise  proc PUBLIC
LOCAL pIConnectionPointContainer,m_pIConnectionPoint,m_dwCookie,dwRegister
xor ecx,ecx
mov pIConnectionPointContainer,ecx
mov m_pIConnectionPoint,ecx
mov m_dwCookie,ecx
.if !Inst__ClsForTest
mov Inst__ClsForTest,rv(__ClsForTest@CreateInterface)
.endif
;------------------------------------------ Class.QueryInterface IConnectionPointContainer
LEA ECX, pIConnectionPointContainer
PUSH ECX
lea eax ,IID_IConnectionPointContainer
    PUSH EAX
    MOV EDX,Inst_ClsForTest
    PUSH EDX
    MOV EDX,[EDX]
    CALL DWORD PTR [EDX];QueryInterface
   
        .if pIConnectionPointContainer
        invoke crt_wprintf,cfm$("\n QueryInterface IConnectionPointContainer OK ")
;------------------------------------------ IConnectionPointContainer.FindConnectionPoint
LEA ECX, m_pIConnectionPoint
PUSH ECX
lea eax ,IID___ClsForTest
    PUSH EAX
    MOV EDX,pIConnectionPointContainer
    PUSH EDX
    MOV EDX,[EDX]
    CALL DWORD PTR [EDX+16];FindConnectionPoint
.if m_pIConnectionPoint
    MOV EDX,pIConnectionPointContainer
    PUSH EDX
    MOV EDX,[EDX]
    CALL DWORD PTR [EDX+8];release
        invoke crt_wprintf,cfm$("\n FindConnectionPoint OK")
;------------------------------------------ FindConnectionPoint.Advise
LEA ECX, m_dwCookie
PUSH ECX
lea ecx,Inst__ClsForTest
    PUSH ecx 
    MOV EDX,m_pIConnectionPoint
    PUSH EDX
    MOV EDX,[EDX]
    CALL DWORD PTR [EDX+20];Advise
    .if eax == S_OK
        invoke crt_wprintf,cfm$("\n Advise OK ")
.else
        invoke crt_wprintf,cfm$("\n Advise Failer eax:=0x%Xh"),eax
    .endif
.else
        invoke crt_wprintf,cfm$("\n FindConnectionPoint Failer")
.endif
        .else
        invoke crt_wprintf,cfm$("\n IConnectionPointContainer Failer")
        .endif
ret
__ClsForTest@Advise endp

and after invoke _ClsForTest@MethodForTest : add
invoke __ClsForTest@Advise


then add another  invoke _ClsForTest@MethodForTest for test if the event is fired
The final code as follows: __UNICODE__ equ 1
include \masm32\include\masm32rt.inc
.data
IID_IUnknown GUID <000000000H,00000H,00000H,<0C0H,000H,000H,000H,000H,000H,000H,046H>>
IID_IConnectionPointContainer GUID <0B196B284h,0BAB4h,0101Ah,<0B6h,09Ch,000h,0AAh,000h,034h,01Dh,007h>>

include Ev_ClsForTest.inc
include Cls_ClsForTest.inc
.code
Start:
invoke CoInitializeEx, NULL,COINIT_MULTITHREADED    ;COINIT_APARTMENTTHREADED ;
.if rv( _ClsForTest@CreateClass); Create New ClsForTest
invoke _ClsForTest@MethodForTest ;ClsForTest.MethodForTest
invoke __ClsForTest@Advise
invoke _ClsForTest@MethodForTest ;ClsForTest.MethodForTest
invoke _ClsForTest@Release ; ClsForTest.Release
.endif
invoke CoUninitialize
inkey
exit
End Start


Switch between COINIT_MULTITHREADED   and COINIT_APARTMENTTHREADED at CoInitializeEx; then tell me what's going on
Title: Re: COM Events
Post by: mabdelouahab on April 26, 2015, 01:45:41 AM
At here everything is working fine; We have succeeded in working with InprocServer DLL
So
I created the same ٍVB project, But this time with EXE Active X
Alert: I added event 2
Public Event EventForTest()
Public Event EventForTest2()

Public Sub MethodForTest()
    MsgBox "Hi Is Me ..."
    RaiseEvent EventForTest2
    RaiseEvent EventForTest
End Sub

And I created a second Masm project for working with the new VB project , But the strange thing this time everything well
Quote
CreateClass _ClsForTest OK
QueryInterface IConnectionPointContainer OK
FindConnectionPoint OK
__ClsForTest@QueryInterface
__ClsForTest@QueryInterface
__ClsForTest@QueryInterface
__ClsForTest@QueryInterface
__ClsForTest@QueryInterface
__ClsForTest@AddRef
__ClsForTest@QueryInterface
__ClsForTest@QueryInterface
__ClsForTest@QueryInterface
__ClsForTest@QueryInterface
__ClsForTest@QueryInterface
__ClsForTest@QueryInterface
__ClsForTest@QueryInterface
__ClsForTest@QueryInterface
__ClsForTest@QueryInterface
__ClsForTest@Release
__ClsForTest@QueryInterface
__ClsForTest@AddRef
Advise OK
__ClsForTest@QueryInterface
__ClsForTest@QueryInterface
__ClsForTest@Release
__ClsForTest@AddRef
__ClsForTest@_Invoke 2
__ClsForTest@MethodForTest
__ClsForTest@_Invoke 1
__ClsForTest@MethodForTest
__ClsForTest@Release
__ClsForTest@Release
__ClsForTest@Release
__ClsForTest@QueryInterface
__ClsForTest@QueryInterface
__ClsForTest@ReleasePress any key to continue ...
Don't forget Reg.Bat to register exe server
Title: Re: COM Events
Post by: mabdelouahab on April 26, 2015, 01:51:43 AM
What happens to me
This time everything worked
Everything went correctly
What we neglect in the past  :redface:
Title: Re: COM Events
Post by: mabdelouahab on April 26, 2015, 04:53:20 AM
Dave , Zen ,adeyblue ,jj2007 , Biterider ,Gunther .. Thank you all  :t, Forum members, Thank everyone
Title: Re: COM Events
Post by: Gunther on April 26, 2015, 08:28:11 PM
Hi mabdelouahab,

Quote from: mabdelouahab on April 26, 2015, 04:53:20 AM
Dave , Zen ,adeyblue ,jj2007 , Biterider ,Gunther .. Thank you all  :t, Forum members, Thank everyone

it was our pleasure to help you.

Gunther