Thread overview
Problem with COM interfaces
Apr 12, 2005
Dick L
Apr 12, 2005
Chris Sauls
Apr 12, 2005
dickl
simplied code showing the COM problem
Apr 14, 2005
Dick L
Apr 15, 2005
Thomas Kuehne
Apr 15, 2005
Dick L
There are two types of COM interfaces
Apr 15, 2005
Dick L
April 12, 2005
The compiler seems to doing strange things when calling a COM interface methods: E.g.

interface foo: IUnknown
{
    extern(Windows) int getDrivername(char *name);
}


...
code to initialize COM and get the pointer to the interface seems to work
correctly.

Now when calling getDrivername, the compiler seems to push extra stuff on
the stack which caused the stack to get corrupted and memory to get
corrupted as getDrivername writes to the wrong address
e.g.

   char []name;
   char *p=name; //for viewing during debuging
   theinterface.getDrivername(p);


the assembly looks like this:
char *p=name;
004030B9 lea edx,[esi+8]
004030BC mov dword ptr [p],edx

theinterface.getDrivername(p);
004030BF push edx                             // the address of the string
004030C0 mov ebx,dword ptr [this]     // now the address of the interface is
pushed on the stack
004030C3 add ebx,10h                        // the interface is expecting
only 1 arg  so there now are stack problems
004030C6 mov eax,dword ptr [ebx]     // the interface thinks this is the ptr
to write to so memory gets corrupted
004030C8 push eax
004030C9 mov edi,dword ptr [eax]     // the interface method is called
(correctly)
004030CB call dword ptr [edi+10h]


April 12, 2005
Dick L wrote:
>    char []name;
>    char *p=name; //for viewing during debuging
>    theinterface.getDrivername(p);

Try the following -- which I admit to not having tested:
# char[] name;
# char*  p = name.ptr;
# theinterface.getDrivername(p);

Or maybe even just:
# char[] name;
# theinterface.getDrivername(cast(char*)name.ptr);

-- Chris Sauls
April 12, 2005
The problem is not related to the pointer being passed.

Oddly enough, what seems to work is declaring all the
methods in the interface as extern(D) rather than extern(Windows)

Chris Sauls wrote:
> Dick L wrote:
> 
>>    char []name;
>>    char *p=name; //for viewing during debuging
>>    theinterface.getDrivername(p);
> 
> 
> Try the following -- which I admit to not having tested:
> # char[] name;
> # char*  p = name.ptr;
> # theinterface.getDrivername(p);
> 
> Or maybe even just:
> # char[] name;
> # theinterface.getDrivername(cast(char*)name.ptr);
> 
> -- Chris Sauls
April 14, 2005
The following bit of code shows the compiler pushing the address of the
interface on the stack before calling
the interface method.
When extern(Windows) is changed to extern(D) the compiler doesn't do that.

module test;
interface foo
{
extern(Windows):
    int getName(char *p);
    int init(void *);
}
int main()
{
    foo theInterface;
    char []Name;
    theInterface.getName(cast(char *)Name);
    return true;
}

int main()
00402010 enter 10h,0
{
    foo theInterface;
    00402014 xor eax,eax
    00402016 mov dword ptr [theInterface],eax
    char []Name;
    00402019 mov dword ptr [Name],eax
    0040201C mov dword ptr [ebp-4],eax
    theInterface.getName(cast(char *)Name);
    0040201F push dword ptr [ebp-4]
    00402022 push eax
    00402023 mov ecx,dword ptr [eax]
    00402025 call dword ptr [ecx+4]
    return true;


===========================
module test;
interface foo
{
extern(D):
    int getName(char *p);
    int init(void *);
}
int main()
{
    foo theInterface;
    char []Name;
    theInterface.getName(cast(char *)Name);
    return true;
}
int main()
00402010 enter 10h,0
{
    foo theInterface;
    00402014 xor eax,eax
    00402016 mov dword ptr [theInterface],eax
    char []Name;
    00402019 mov dword ptr [Name],eax
    0040201C mov dword ptr [ebp-4],eax
    theInterface.getName(cast(char *)Name);
    0040201F push dword ptr [ebp-4]
    00402022 mov ecx,dword ptr [eax]
    00402024 call dword ptr [ecx+4]
    return true;


April 15, 2005
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Dick L schrieb am Thu, 14 Apr 2005 09:54:23 -0400:
> The following bit of code shows the compiler pushing the address of the
> interface on the stack before calling
> the interface method.
> When extern(Windows) is changed to extern(D) the compiler doesn't do that.
<snip>

Could someone please write a test case that checks for this via assert? (My Windows knowledge is very limited, so I done't know what to expect)

Thomas


-----BEGIN PGP SIGNATURE-----

iD8DBQFCXxzX3w+/yD4P9tIRAtenAJ9hfO4iSctytJJkMVUqamjoJPkslACfeR2r
b7lHikSTNlhucEPhcqgTJ1A=
=L4Rf
-----END PGP SIGNATURE-----
April 15, 2005
I'll do it..

I'd like to get some confirmation its a compiler bug rather than my stupidity before I do..

dick
"Thomas Kuehne" <thomas-dloop@kuehne.thisisspam.cn> wrote in message
news:nvi3j2-8re.ln1@lnews.kuehne.cn...
>
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> Dick L schrieb am Thu, 14 Apr 2005 09:54:23 -0400:
>> The following bit of code shows the compiler pushing the address of the
>> interface on the stack before calling
>> the interface method.
>> When extern(Windows) is changed to extern(D) the compiler doesn't do
>> that.
> <snip>
>
> Could someone please write a test case that checks for this via assert? (My Windows knowledge is very limited, so I done't know what to expect)
>
> Thomas
>
>
> -----BEGIN PGP SIGNATURE-----
>
> iD8DBQFCXxzX3w+/yD4P9tIRAtenAJ9hfO4iSctytJJkMVUqamjoJPkslACfeR2r
> b7lHikSTNlhucEPhcqgTJ1A=
> =L4Rf
> -----END PGP SIGNATURE----- 


April 15, 2005
After a little more research it appears there are two types of COM
interfaces:
The first requires the 'this' pointer of the interface to be past when
calling methods. E.g. Direct X
The second does not expect a this pointer to be pasted. E.g. interfaces
written in C

 I wrote a simple test in CPP and it seems the default behaviour for the
MSVC compiler is to
not pass the 'this' pointer.  The MSC header files for all the MS interfaces
seem to work some magic
and tell the compiler to pass the this pointer. Hard to tell what is going
on with all the header files included, macros and #defined stuff in there.

So.... I think simplest thing to do is update the interface documentation to
say the default D implementation will pass a pointer
to the interface when calling the interface methods. If you don't want the
this pointer to be passed, declare the interface as "extern(D)". It would
probably be better if "extern(C)" did this as its a little more obvious.