News:

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

Main Menu

Implementation of the COM interface FileOpenDialog

Started by jorgon, February 19, 2025, 11:31:58 AM

Previous topic - Next topic

jorgon

It turns out this is easier to code in assembler than in "C" because everything is obvious and there are no compiler quirks to be circumvented.  The attached asm file of 6KB (renamed FileOpenDialog.txt so it can be uploaded to the forum) contains all the code and there are no includes!  When assembled and linked, this simple program shows a Windows open file dialog and displays the chosen file in a message box.  This also demonstrates using iShellItem to assist in the process.

[EDIT] Sorry couple of small changes to the attachment - changed flag to CoInitializeEx and slight change to Release call

NoCforMe

OK, I'm looking at that.
So what is the advantage of using that, what with all the CoInvoke stuff required, over just using the standard Win32 GetOpenFileName(), which I use all the time?
Setting up that dialog is pretty simple and doesn't require all that C++ baggage.
Assembly language programming should be fun. That's why I do it.

jorgon

Well, the Windows documentation says:
QuoteStarting with Windows Vista, the Common Item Dialog supersedes the older Common File Dialog when used to open or save a file. The Common Item Dialog is used in two variations: the Open dialog and the Save dialog. These two dialogs share most of their functionality, but each has its own unique methods.
and
QuoteThe Common Item Dialog implementation found in Windows Vista provides several advantages over the implementation provided in earlier versions:

Supports direct use of the Shell namespace through IShellItem instead of using file system paths.
Enables simple customization of the dialog, such as setting the label on the OK button, without requiring a hook procedure.
Supports more extensive customization of the dialog by the addition of a set of data-driven controls that operate without a Win32 dialog template. This customization scheme frees the calling process from UI layout. Since any changes to the dialog design continue to use this data model, the dialog implementation is not tied to the specific current version of the dialog.
Supports caller notification of events within the dialog, such as selection change or file type change. Also enables the calling process to hook certain events in the dialog, such as the parsing.
Introduces new dialog features such as adding caller-specified places to the Places bar.
In the Save dialog, developers can take advantage of new metadata features of the Windows Vista Shell.

NoCforMe

Okay, good answer.
One question: where do you find the documentation for all of those "methods" and other stuff needed to implement COM in assembly language?
Assembly language programming should be fun. That's why I do it.

jorgon

#4
Well, the Windows documentation is available online at https://learn.microsoft.com/en-gb/ but in the case of COM you would be hard pressed to be able to work from that alone. There are examples there in "C++" so it's a matter of using those examples to get back to basics by trying to rewrite the example in assembler and then with a bit of experimentation eventually things start to work ..
One problem is that COM can be, or must be, implemented in several different ways as can be seen from the examples at http://www.godevtool.com

jj2007

Hi Jorgon,

Welcome back :thup:

I have the same questions as NoCForMe, thanks for answering them. In practice, we have found ways to implement the new features with the old version but still, your code is extremely useful. Sooner or later it's time to throw the old FileOpen/FileSave stuff into the dustbin :cool:

NoCforMe

Quote from: jorgon on February 19, 2025, 04:31:28 PMWell, the Windows documentation is available online at https://learn.microsoft.com/en-gb/ but in the case of COM you would be hard pressed to be able to work from that alone. There are examples there in "C++" so it's a matter of using those examples to get back to basics by trying to rewrite the example in assembler and then with a bit of experimentation eventually things start to work ..
One problem is that COM can be, or must be, implemented in several different ways as can be seen from the examples at http://www.godevtool.com

Thanks, but I wonder if you could post at least one of those C++ examples (or just a link to one).

But even if one has such an example, how does one get the contents with which to populate the needed structures, like, say, IFileOpenDialog? Aren't all those things hidden within the C++ classes or methods or whatever? or do those functions all exist explicitly in the C++ code?
Assembly language programming should be fun. That's why I do it.

NoCforMe

Wait just a minute: I just looked at those jump tables (that's what they are, right? or some other kind of dispatching table), and they're all zeroes. How does that work???
Assembly language programming should be fun. That's why I do it.

jorgon

They're all structures.
STRUCT-ENDS in GoAsm declares a structure.
Yes it's true the zeroes could have been left out, but I quite like them.

And the blurb says:
QuoteHere is a structure declaration containing the vtable for the FileOpenDialog interface.
At compile time this gives the offset into the vtable of the particular function being called
This table comes from ShObjidl_core.h

The vtable is in Windows data/memory and at runtime all you have is a pointer to it (in iFILEOPENDIALOG).
And you get the offset into that table for the function from the structure.
So for example if you want to call "Show" the structure tells you that the offset is +0Ch

And so the actual call is:
MOV EAX,[iFILEOPENDIALOG]
CALL [EAX+0Ch]

That is dealt with by the CoInvoke macro.

jorgon


NoCforMe

Quote from: jorgon on February 20, 2025, 03:59:54 PMThey're all structures.

Yeah, yeah, I get that: I'm an assembler programmer, even though I don't use GoAsm.
But what I don't get is:
QuoteAnd so the actual call is:
MOV EAX,[iFILEOPENDIALOG]
CALL [EAX+0Ch]

That is dealt with by the CoInvoke macro.

But from looking at the source you provided, the value of [EAX+0Ch] is zero, right? Which of course would result in a fault.

Does that vtable get filled in at runtime somehow magically?
Assembly language programming should be fun. That's why I do it.

NoCforMe

Quote from: jorgon on February 20, 2025, 04:06:08 PM
Quote from: NoCforMe on February 20, 2025, 02:55:28 PMThanks, but I wonder if you could post at least one of those C++ examples (or just a link to one).

https://learn.microsoft.com/en-us/windows/win32/learnwin32/example--the-open-dialog-box
Nowhere in that example do I see any of those vtable members you put in your structures.
Where do those come from?
Assembly language programming should be fun. That's why I do it.

jorgon

In:
MOV EAX,[iFILEOPENDIALOG]
CALL [EAX+0Ch]

First line: EAX is given a pointer to the vtable held in Windows memory/data.
Second line: your exe calls the value 12 bytes into the vtable held in Windows memory/data. This is the address in the Windows code of the function that your exe wants to call.

This address is a value put into the vtable held in Windows memory/data when the COM interface is loaded.  This address will probably change from time to time as the COM dlls are updated.

jorgon

Quote from: NoCforMe on February 20, 2025, 04:19:14 PMNowhere in that example do I see any of those vtable members you put in your structures.
Where do those come from?

As mentioned in my file the vtable members come from the Windows header file ShObjidl_core.h

But they are probably also in shobjidl.h which is given as an include file in the C++ example.  That's one reason why I don't like to use includes.  You would have to search the include file to understand how the example code works.

NoCforMe

Quote from: jorgon on February 20, 2025, 04:33:47 PM
Quote from: NoCforMe on February 20, 2025, 04:19:14 PMNowhere in that example do I see any of those vtable members you put in your structures.
Where do those come from?

As mentioned in my file the vtable members come from the Windows header file ShObjidl_core.h

But they are probably also in shobjidl.h which is given as an include file in the C++ example.  That's one reason why I don't like to use includes.  You would have to search the include file to understand how the example code works.

OK. So where does one get those files? I don't have any C compilers here, no Visual Studio, none of that stuff.
Sorry to keep bugging you, but your answers only trigger more questions.
Assembly language programming should be fun. That's why I do it.