www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - Problem with COM interfaces

reply "Dick L" <dick221z yahoo.com> writes:
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] 
Apr 11 2005
next sibling parent reply Chris Sauls <ibisbasenji gmail.com> writes:
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
Apr 11 2005
parent dickl <dick221z yahoo.com> writes:
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

Apr 12 2005
prev sibling next sibling parent reply "Dick L" <dick221z yahoo.com> writes:
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; 
Apr 14 2005
parent reply Thomas Kuehne <thomas-dloop kuehne.thisisspam.cn> writes:
-----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.

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-----
Apr 14 2005
parent "Dick L" <dick221z yahoo.com> writes:
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.

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

Apr 14 2005
prev sibling parent "Dick L" <dick221z yahoo.com> writes:
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.
Apr 15 2005