Member names lost in unnamed nested structures

Started by Yuri, February 05, 2010, 08:32:31 AM

Previous topic - Next topic

Yuri

The GoAsm manual reads:
Quote
Like structure members, nested structures need not be named, so that this is perfectly valid:-

StructTest STRUCT
      DD     6
      RECT
    c DD     7
    d DD     8
ENDS


But how can I access the members of the RECT structure? Their names disappear. Perhaps in such a case they should become members of the parent structure and make up symbols StructTest.left, StructTest.top and so on.  ::)

dedndave

well - the elements need not be named - but if you want to access that element, then name it   :U
without the name, it is more or less a place-holder

japheth

Quote from: dedndave on February 05, 2010, 10:05:42 AM
well - the elements need not be named - but if you want to access that element, then name it   :U
without the name, it is more or less a place-holder

True.  :toothy

However, in Masm it's possible to access the members of an embedded, anonymous structure simply by their names:


S1 struct
f1 dd ?
S1 ends

S2 struct
S1 <>
S2 ends

mov eax,[ebx].S2.f1


And my guess is that this is what Yuri is complaining about.


Yuri

Yes, japheth, your guess is correct. I thought such tricks could be useful when defining COM interfaces where one inherits member functions from another so that they become its own immediate members. Here is what I want to do:

IUnknownVtbl STRUCT
    QueryInterface    PTR
    AddRef            PTR
    Release           PTR
ENDS

IDispatchVtbl STRUCT    ; Inherits from IUnknown.
    IUnknownVtbl
    GetTypeInfoCount    PTR
    GetTypeInfo         PTR
    GetIDsOfNames       PTR
    Invoke              PTR
ENDS

SomeOtherVtbl STRUCT    ; Inherits from IDispatch.
    IDispatchVtbl
    Func1        PTR
    Func2        PTR
ENDS


So that later I could call any of the inherited functions directly:

call [eax+SomeOtherVtbl.QueryInterface]
call [eax+SomeOtherVtbl.Invoke]


donkey

Believe me when I started using COM with GoAsm I did look at a way of getting the vtables working the way you wanted and ended up with the compromise I used, much of the current functionality of structures (ie unions) were not yet implemented. The other option is to explicitly name each of the members of IUnknown, though it would make for marginally larger files it would meet your requirement. In the end GoAsm is not MASM nor is it C++, interface vtable definitions are not natively supported and for the longest time I was the only person doing any real COM stuff in GoAsm so the headers tended to follow how I preferred to do it. By the time others began to use COM and the capabilities of structures were enhanced it would have broken too much exisiting software (mostly mine) to change it and since it is essentially correct, being only a syntax issue I left it as is.

However, it is possible to modify the headers so that both syntax are allowed, I will work on it and it will be incorporated in some future release, probably next week some time. The solution is this:

ISomeinterface STRUCT
UNION
struct
QueryInterface PTR
AddRef PTR
Release PTR
ends
IUnknown Unknown
ENDUNION
// Interface pointers here
ENDS


This will not break any current code and it will satisfy your syntax requirements. However, there is no way that I know of to do real "inherits from" type vtables, that simply can't be done at the moment so I see no reason to distinguish between interface and vtable as they are the same thing when considering GoAsm capabilities.

Edgar
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

donkey

Hi Yuri,

I love using RadASM as an editor, makes things so incredibly quick. I have completed the update of the headers as I mentioned above, both IUnknown and IDispatch methods are now available using either of the following

CoInvoke(pInterface,ISomeinterface.Release)

or

CoInvoke((pInterface,ISomeinterface.IUnknown.Release)

Having an issue uploading the headers though so I the update is not available on my website just yet, it will be as soon as I can get this worked out. The process of changing them was automated so there should be no issues. I tried the headers out on a few COM projects without any problems.

Edgar
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

donkey

Hi Yuri,

The upload of version 0x021004 should solve your problem. It is now available on my site.

Edgar
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

Yuri

Thank you very much for your time and effort, Edgar! I have downloaded and tested the new headers. Your current solution looks very promising, indeed. In fact, the difference between IInterface and IInterfaceVtbl was the lesser of my problems, I was more bothered by the necessity to insert IUnknown and IDispatch in the middle of every call. Much like in your case, it's the way of thinking I'm used to. As for Vtbl, at least omitting it will save me 4 characters in typing.

However, I'm now having trouble with this test code:

#define LINKFILES
#define LINKVCRT
#define WIN32_LEAN_AND_MEAN
#include <windows.h>


DATA SECTION

disp    STANDARD_DISPATCH <<<1, 2, 3>>, <<11, 12, 13, 14>>>

CODE SECTION

Start:
    invoke printf, "%d %d %d %d %d %d %d", [disp.QueryInterface], [disp.AddRef], [disp.Release], \
         [disp.GetTypeInfoCount], [disp.GetTypeInfo], [disp.GetIDsOfNames], [disp.Invoke]
    add esp,20h
    ret


When I try to assemble it, GoAsm returns this error message:
Quote
GoAsm.Exe Version 0.56.8 - Copyright Jeremy Gordon 2001/9 - JG@JGnet.co.uk

Error!
Line 9 of assembler source file (interface.asm):-
Invalid data/structure/union declaration in implementation of structure:-
<<<1, 2, 3>>, <<11, 12, 13, 14>>>
  In the struct at Line 22 of the include file BaseCOM.h

However, this version compiles OK:

#define LINKFILES
#define LINKVCRT
#define WIN32_LEAN_AND_MEAN
#include <windows.h>


DATA SECTION

disp    STANDARD_DISPATCH <<<1, 2, 3>, <4, 5, 6>>, <<11, 12, 13, 14>, <15, 16, 17, 18>>>

CODE SECTION

Start:
    invoke printf, "%d %d %d %d %d %d %d", [disp.QueryInterface], [disp.AddRef], [disp.Release], \
         [disp.GetTypeInfoCount], [disp.GetTypeInfo], [disp.GetIDsOfNames], [disp.Invoke]
    add esp,20h
    ret


And this is the output of printf:
Quote
4 5 6 15 16 17 18

Obviously something goes wrong here. I'll do some more testing to figure out what exactly it is.

donkey

#8
Hi Yuri,

It appears to be a problem when there is more than 1 structure in the union, it doesn't seem to make a difference whether they are named or not, or unrolled or not. I am trying to find a syntax for declaring them with data that works but no luck yet.

Edgar

EDIT: There is a serious issue with initializing unions here

SUBTESTINIT STRUCT
mem1 DD
mem2 DD
mem3 DD
ENDS

TESTINIT STRUCT
UNION
struct
mem1 DD
mem2 DD
mem3 DD
ends
substruct SUBTESTINIT
ENDUNION
ENDS

DATA SECTION
testinit    TESTINIT <1, 2, 3>


Yeilds 1 0 0, it should be 1 2 3

A dump of memory shows that only the first byte of each is written:

testinit    TESTINIT <1, 2, 3>, <4, 5, 6>, <7, 8, 9>

Line 52: ### DbgDump 32 bytes (00403029 to 00403048)
00403029:  01 00 00 00-00 00 00 00-00 00 00 00-04 00 00 00   ................
00403039:  00 00 00 00-00 00 00 00-07 00 00 00-00 00 00 00   ................


In the original structure

STANDARD_DISPATCH STRUCT
UNION
struct
QueryInterface PTR
AddRef PTR
Release PTR
ends
IUnknown Unknown
ENDUNION
UNION
struct
GetTypeInfoCount PTR
GetTypeInfo PTR
GetIDsOfNames PTR
Invoke PTR
ends
IDispatch Dispatch
ENDUNION
ENDS


all of the offsets are reported correctly, this appears to only happen when it is initialized with data, this one is for Jeremy.
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

Yuri

This way it sort of works:

#define LINKFILES
#define LINKVCRT
#define WIN32_LEAN_AND_MEAN
#include <windows.h>


DATA SECTION

disp    STANDARD_DISPATCH <{QueryInterface=1, AddRef=2, Release=3, \
          GetTypeInfoCount=11, GetTypeInfo=12, GetIDsOfNames=13, Invoke=14}>

CODE SECTION

Start:
    invoke printf, "%d %d %d %d %d %d %d", [disp.QueryInterface], [disp.AddRef], [disp.Release], \
        [disp.GetTypeInfoCount], [disp.GetTypeInfo], [disp.GetIDsOfNames], [disp.Invoke]
    add esp,20h
    ret


But look at printf's output:
Quote
1 2 3 11 11 13 14

Perhaps there's a limitation for how many characters of a member name are used for its identification.

donkey

Quote from: Yuri on February 06, 2010, 08:33:41 AM
Perhaps there's a limitation for how many characters of a member name are used for its identification.

You're right, but it only seems to be during initialization, when moving data into the members or calculating the offsets everything works fine
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable