News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

COM Events

Started by mabdelouahab, April 16, 2015, 05:50:24 PM

Previous topic - Next topic

mabdelouahab

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 , Called CoCreateFreeThreadedMarshaler

Does anyone have information on what happens in the background?



dedndave

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

Zen

#17
MABDELOUAHAB,
Here is an excellent article that explains COM Events: Understanding COM Event Handling, CodeProject
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.

Also, you may find this MSDN reference section informative: COM Interop (Visual Basic)

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

jj2007

Quote from: Zen on April 19, 2015, 03:17:03 AMHere is an excellent article that explains COM Events: Understanding COM Event Handling, CodeProject

Excellent article indeed :t
If I had unlimited time and no other projects, I would give it a try.

Zen

...So,...I don't see any reason,...given all this pertinent information,...why MABDELOUAHAB's project cannot be correctly implemented,...


jj2007

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

mabdelouahab

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
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
//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;
}



Zen

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 ?

mabdelouahab

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) 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

Biterider

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

mabdelouahab

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

Zen

#26
MABDELOUAHAB,
The CodeProject has a large number of articles about COM programming: COM / COM+
Here is the section for: COM/DCOM/COM+ - Beginners
These articles are excellent:
Introduction to COM - What It Is and How to Use It
Introduction to COM Part II - Behind the Scenes of a COM Server
The COM Macro-Architecture Topology
COM Macro Architecture Topology - Servers
COM Macro Architecture Topology - Clients
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
COM in Plain C, Part Two
COM in Plain C, Part Three
COM in Plain C, Part Four
COM in Plain C, Part Five
COM in Plain C, Part Six
COM in Plain C, Part Seven
COM in Plain C, Part Eight

...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. and, ActiveX EXE Wrappers

...And,...if you are serious about COM programming,...there is no better reference than: Essential COM, Don Box


adeyblue

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.

Zen

MABDELOUAHAB,
Here is an internet archive (the Wayback machine) of Japheth's Site: Japheth's Site, COM & Assembly
...Scroll down the left side Menu to Miscellaneous, COM & Assembly,...
All his original MASM COM Source Code examples are located there and downloadable,...

mabdelouahab

I have found some answers, but I'm trying scattered work Like
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