News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

Exploring COM

Started by sinsi, December 20, 2019, 02:18:26 AM

Previous topic - Next topic

sinsi

I have been playing with COM (interfaces and such) and everything seems to work OK, but I would like to know
if my assumptions are correct since C++ is a mystery to me.

1. When we ask for an interface, we supply a memory location to be filled with the address of the interface, which is really a structure.
2. The structure address is "this" and is (usually? always?) the first parameter.
3. I have read about ECX having the "this" parameter but is that only for C++ objects? Or COM as well?
4. If a call returns a memory block (allocated by the interface, not my code) it has to be freed by a call to e.g. CoTaskMemFree.
    ExitProcess will not free this memory, but does Release?

Searching gives me lots of HLL stuff (which is to be expected after all), but no low-level stuff, possibly because I don't know the terminology :biggrin:

Biterider

Hi Sinsi
1. When we ask for an interface, we supply a memory location to be filled with the address of the interface, which is really a structure.
Right. There is an important fact, that the returned interface pointers are internally tracked with a counter. Each time you request an interface, the counter is incremented and decremented when you release it. When the count is zero, in most cases, the object is destroyed.
2. The structure address is "this" and is (usually? always?) the first parameter.
The first slot in the interface structure is a pointer to a virtual table. This table holds the addresses of the methods that can be called using this interface. The sequence of addresses in the virtual table is given by the declaration of the interface. Be careful, some documentation is sorted alphabetically and not by sequence!
3. I have read about ECX having the "this" parameter but is that only for C++ objects? Or COM as well?
This is true for C++, but you are free to use any register. Don't assume that the this pointer is in rcx/ecx.
4. If a call returns a memory block (allocated by the interface, not my code) it has to be freed by a call to e.g. CoTaskMemFree.  ExitProcess will not free this memory, but does Release?
In most cases yes, but you have to read the documentation in each case.

COM is a lot about standards and documentation.  :biggrin:

Biterider

sinsi

QuoteBe careful, some documentation is sorted alphabetically and not by sequence!
I can usually sort out the header files :badgrin:

QuoteCOM is a lot about standards and documentation.  :biggrin:
And knowing the terminology - why is it called an apartment???

nidud

#3
deleted

Biterider

Hi
QuoteAnd knowing the terminology - why is it called an apartment???
It is a bit of story behind this. COM was born as single threading and in a sigle process. As time goes on, multitreading and interprocess communication was added and things became a bit complicated. Later, net distributed communication was added too. So DCOM was born. It wasn't very successful due to the proxy/server and mashalling difficulties.
MS stepped back and uses today mostly only the interfaces to access the modern APIs.

Biterider

jj2007

Quote from: sinsi on December 20, 2019, 02:18:26 AM
ExitProcess will not free this memory, but does Release?

What makes you think that ExitProcess will not free this memory? The docs are usually vague about this, if you have a good source, I'd be curious to see it...

Raymond Chen on ExitProcess
QuoteDon't worry about freeing memory; it will all go away when the process address space is destroyed

sinsi

Quote from: jj2007 on December 20, 2019, 06:46:09 AM
What makes you think that ExitProcess will not free this memory? The docs are usually vague about this, if you have a good source, I'd be curious to see it...
Poor wording on my part, ExitProcess will free the memory, as it's part of my process's virtual address space, but does the interface keep any sort of internal pointer?
If so, how will it know that there is no memory there any more?

An example from IShellItem::GetDisplayName
QuoteIt is the responsibility of the caller to free the string pointed to by ppszName when it is
no longer needed. Call CoTaskMemFree on *ppszName to free the memory.

Another example, if I use IPreviewHandler on a .pdf I can see the previewer in task manager, it exits when the preview is closed (IPreviewHandler::Unload).
Except for previewing .docx files with Word, sometimes even after my program releases all interfaces and exits, Word is still running - no window so no way of closing it.
The consequences of this are having several word.exe running and, interestingly, having several blank word documents open when Windows restarts  :rolleyes:


Thanks for the replies and reassurance  :thumbsup:

jj2007

Quote from: sinsi on December 20, 2019, 11:48:10 AMExitProcess will free the memory, as it's part of my process's virtual address space, but does the interface keep any sort of internal pointer?

Good question! Is the interface part of the process's virtual address space? In that case, it will be killed by ExitProcess, too. If not, i.e. if the interface is a separate process, how do our process and the COM process communicate with each other?

I've tried to understand Larry Osterman's Sad Story of CoGetMalloc, but it's a bit late now... maybe you find it inspiring ;-)

There is another post by Osterman: What are these "Threading Models" and why do I care?
Quoteinternally, COM uses windows messages to do inter-thread marshalling

See also CLSCTX enumeration:
Quote
CLSCTX_INPROC_SERVER   The code that creates and manages objects of this class is a DLL that runs in the same process as the caller of the function specifying the class context.

My badly informed guess is that our programs are normally in-process, which implies that the whole COM stuff is being eliminated by ExitProcess.

nidud

#8
deleted

sinsi

Hi nidud, I'm not building a preview handler, I am using IPreviewHandler to use other preview handlers.
I don't see prevhost.exe at all.

My code works and previews files (as long as a preview handler is associated with a file extension) but like a lot of my guesswork around C++ concepts
it's nice to confirm things e.g. my code always stopped after the call to IPreviewHandler.DoPreview. Some experimenting showed me that
using COINIT_APARTMENTTHREADED would fix that (or putting the preview code in another thread, which allows my main window to work). Sigh.

nidud

#10
deleted

sinsi

Here is the code I have, it's messy because I had to convert it to masm32 :biggrin:
A couple of things, masm32 doesn't seem to have uuid.lib, so check the path of includelib, and the preview handler expects a full path to the document.

You can also preview pdf,mp3 etc.

jj2007

No luck on Win7-64 :sad:
AssocQueryString
x:eax           80070483
$Err$()         Operazione completata.__


That is ERROR_NO_ASSOCIATION. But GetLastError says everything is ok, and a double-click on the word doc opens it in Word - mysteries of Windows :biggrin:

It works fine for a pdf doc, though :thumbsup:

... except that I have to kill the process with Ctrl C. Weird :cool:

AssocQueryString        eax             0
CLSIDFromString         eax             0
CoCreateInstance        eax             0
TryUsingStream          eax             0
IPreviewHandler         eax             0
IPreviewHandler         eax             0
IPreviewHandler         eax             0
SafeRelease pst         eax             3
SafeRelease pif         eax             1


No SafeRelease pph :sad:

sinsi

Quote from: jj2007 on December 21, 2019, 09:27:47 PM
That is ERROR_NO_ASSOCIATION. But GetLastError says everything is ok, and a double-click on the word doc opens it in Word - mysteries of Windows :biggrin:
Does Explorer preview the doc?


Biterider

Hi Sinsi
I compiled your example and it works fine on Win10/64 Home.
I tried a pdf file and it fails on the call "covoke  pph,IPreviewHandler,DoPreview" returning 80004005. After that it crashes.
The registy contains the key {8895B1C6-B41F-4C1C-A562-0D564250836F} for the pdf file extension and it previews fine in the explorer... Any idea?  :icon_idea:

Biterider