From: Victor R. <vi...@ua...> - 2004-07-27 10:48:35
|
I have one problem. I hope somebody help me. I install MinGW-3.1.0-1.exe ? minimalist. I wrote this simple code: #include <comcat.h> #include <stdio.h> #include "dllfct.h" class CUnk : public IUnknown { public: virtual HRESULT QueryInterface(REFIID iid, void ** ppvObject); virtual ULONG AddRef(void); virtual ULONG Release(void); }; HRESULT CUnk::QueryInterface(REFIID iid, void ** ppvObject) { return 0; } ULONG CUnk::AddRef(void) { printf("AddRef\n"); return 0; } ULONG CUnk::Release(void) { printf("Release\n"); return 0; } extern "C" __declspec(dllexport) void *tstfunc () { CUnk *p = new CUnk; return p; } Compile with commands: g++ -c -DBUILD_DLL dllfct.cpp dllwrap --output-lib=libtstdll.a --dllname=hello.dll --driver-name=g++ dllfct.o I receive library hello.dll. Next step I wrote code to call my library: IUnknown *pClass = (IUnknown *)tstfunc(); pClass->AddRef(); pClass->Release(); All working Ok. I wrote the same code in MSVC7: typedef void *(*FUNCTION_PTR)(); HMODULE h = LoadLibrary("hello.dll"); FUNCTION_PTR tstfunc; tstfunc = (FUNCTION_PTR)GetProcAddress(h, "tstfunc"); IUnknown *pClass = (IUnknown *)tstfunc(); pClass->AddRef(); pClass->Release(); FreeLibrary(h); But if I call my MINGW library from MSVC7 I receive run time error at line pClass->AddRef(); The function is called(I see ?AddRef ? string in my console). Error is ?Run-Time Check Failure #0. The value of ESP was not property saved across a function call. This is usually a result of calling a function declared with one calling conversion with a function pointer declared with different calling conversion.? ---- http://photo.alkar.net/ |
From: Gisle V. <gi...@bg...> - 2004-07-27 12:41:17
|
"Victor Romanov" <vi...@ua...> said: > But if I call my MINGW library from MSVC7 I receive run time error at line > pClass->AddRef(); The function is called(I see ?AddRef ? string in my > console). Error is ?Run-Time Check Failure #0. The value of ESP was not > property saved across a function call. This is usually a result of calling a > function declared with one calling conversion with a function pointer declared > with different calling conversion.? So, didn't that give you a clue? "CUnk::AddRef()" takes a hidden 'this' pointer. MSVC and g++ passed such a pointer differently. MSCV uses the ECX register while g++ used the stack I believe. A fix is to make AddRef() static or use another call convention than the default/implicit __thiscall. That probably leaves out the virtual. Why should it be virtual anyway? I did't look too closely, but isn't it supposed to count the # of instances of your objects? So would makeing it static work? --gv |
From: Victor R. <vi...@ua...> - 2004-07-27 14:27:01
|
On Tue, 27 Jul 2004 14:41:04 +0200 "Gisle Vanem" <gi...@bg...> wrote: > "Victor Romanov" <vi...@ua...> said: > > > But if I call my MINGW library from MSVC7 I receive run time error at line > > pClass->AddRef(); The function is called(I see ?AddRef ? string in my > > console). Error is ?Run-Time Check Failure #0. The value of ESP was not > > property saved across a function call. This is usually a result of calling > >a > > function declared with one calling conversion with a function pointer > >declared > > with different calling conversion.? > > So, didn't that give you a clue? > > "CUnk::AddRef()" takes a hidden 'this' pointer. MSVC and g++ passed > such a pointer differently. MSCV uses the ECX register while g++ used > the stack I believe. > > A fix is to make AddRef() static or use another call convention than > the default/implicit __thiscall. That probably leaves out the virtual. Why > should it be virtual anyway? I did't look too closely, but isn't it supposed > to count the # of instances of your objects? So would makeing it static > work? > > --gv The object is standard IUnknown. If binary compatibility is different with MSVC it is mean what I can?t from MinGW call the MS Exel, Access controls, DirectX. It is correct? ---- http://photo.alkar.net/ |
From: Michael G. <mg...@te...> - 2004-07-27 16:12:15
|
> The object is standard IUnknown. If binary compatibility is different wit= h=20 > MSVC it is mean what I can?t from MinGW call the MS Exel, Access controls= ,=20 > DirectX. It is correct?=20 I'm not quite sure wether I fully understand what you want to say. However: You are aware that the C++ ABI is *NOT* compatible between compilers. That means that you can't export C++ classes into a DLL and import them from said DLL by another compiler. The main reason for this is that the binary layout of the class objects is not standardized and thus may (and definitely does !) differ between compilers. The different name mangling schemes are supposed to be there to emphasize that point since that way you can't link and thus get something like an "early warning". That having said: IIRC to interface with Excel you only have to use __stdcall (or APIENTRY or WINAPI; they are all the same) calling convention. That one is a C ABI and works from MSVC to MinGW and back again (I'm dead sure about that because among other things I have a couple of such applications installed at clients...). HTH, best, Michael =2D-=20 Vote against SPAM - see http://www.politik-digital.de/spam/ Michael Gerdau email: mg...@te... GPG-keys available on request or at public keyserver |
From: Victor R. <vi...@ua...> - 2004-07-27 17:07:27
|
>That having said: >IIRC to interface with Excel you only have to use __stdcall >(or APIENTRY or WINAPI; they are all the same) calling convention. >That one is a C ABI and works from MSVC to MinGW and back again >(I'm dead sure about that because among other things I have a >couple of such applications installed at clients...). I don't sure or may I something not understand. Like you can see in my sample from previous message I create by MinGW class derived from IUnknown. For both compilers this class must have the same binary representation in memory. In another case all COM calls will not be work. May be I must compile with some keys or do something... |
From: John G. <jo...@jo...> - 2004-07-27 19:19:40
|
Victor Romanov wrote: > For both compilers this class must have the same binary > representation in memory. Not necessarily. Different compilers may order object members differently, align them on memory offsets differently, etc. The only guarantee is that an object will contain given variables of given types. Perhaps you are confusing calling conventions with memory representation? There are a couple different calling conventions in C, but C++ adds vtables and other mechanisms to make inheritence possible. This changes yet again how functions are called and to some extent objects' "binary representations" in memory. I think I understand what you mean, but like I said above, I think you are getting confused about something here. > In another case all COM calls will not be work. May be I must compile > with some keys or do something... COM is, at its core, a way to implement certain object-oriented functionality in non-object-oriented code. As such it is inherently C-based, although it does work fine with C++. Anyway, C code is far more portable between compilers because of the lack of vtables and name mangling. -- John Gaughan http://www.johngaughan.net/ jo...@jo... |
From: Victor R. <vi...@ua...> - 2004-07-27 20:53:38
|
>COM is, at its core, a way to implement certain object-oriented >functionality in non-object-oriented code. As such it is inherently >C-based, although it does work fine with C++. Anyway, C code is far more >portable between compilers because of the lack of vtables and name mangling. Thank you, I will try to solve this problem like you write. I do not think about this idea. |
From: Greg C. <chi...@mi...> - 2004-07-27 22:58:12
|
John Gaughan wrote: > Victor Romanov wrote: > >> In another case all COM calls will not be work. May be I must compile >> with some keys or do something... > > > COM is, at its core, a way to implement certain object-oriented > functionality in non-object-oriented code. As such it is inherently > C-based, although it does work fine with C++. Anyway, C code is far more > portable between compilers because of the lack of vtables and name > mangling. The link to aegisknight.org on this page: http://www.mingw.org/MinGWiki/index.php/MixingCompilers explores ways to make this work. |
From: Michael G. <mg...@te...> - 2004-07-27 20:08:33
|
> >That having said: > >IIRC to interface with Excel you only have to use __stdcall > >(or APIENTRY or WINAPI; they are all the same) calling convention. > >That one is a C ABI and works from MSVC to MinGW and back again > >(I'm dead sure about that because among other things I have a > >couple of such applications installed at clients...). >=20 > I don't sure or may I something not understand. Like you can see in my > sample from previous message I create by MinGW class derived from IUnknow= n. That's why I said the C++ ABI (Application Binary Interface) is not compatible between compilers. > For both compilers this class must have the same binary representation in > memory. Why has that to be ? What you are saying above is "The C++ ABI must be the same for both compilers". That statement is definitely wrong. The binary representation for this class *DIFFERS* for both compilers. That's what "The C++ ABI is different" means. > In another case all COM calls will not be work. May be I must=20 > compile with some keys or do something... I'm not too fluent with COM but OTTOMH I remember COM is a C API (or at least also sports one). To help you with your problem: You can still write the majority of your code using C++, classes etc. (try to avoid exceptions). But you'll have to provide proxy functions that can be called from C if you wish to mix compilers. No big deal, I'm doing that regularly. Best, Michael =2D-=20 Vote against SPAM - see http://www.politik-digital.de/spam/ Michael Gerdau email: mg...@te... GPG-keys available on request or at public keyserver |
From: Victor R. <vi...@ua...> - 2004-07-27 21:03:49
|
> For both compilers this class must have the same binary representation in > memory. >Why has that to be ? >What you are saying above is "The C++ ABI must be the same for both >compilers". >That statement is definitely wrong. The binary representation for >this class *DIFFERS* for both compilers. >That's what "The C++ ABI is different" means. From MSDN: For any given platform (hardware and operating system combination), COM defines a standard way to lay out virtual function tables (vtables) in memory, and a standard way to call functions through the vtables. Thus, any language that can call functions via pointers (C, C++, Small TalkR, Ada, and even Basic) all can be used to write components that can interoperate with other components written to the same binary standard. The double indirection (the client holds a pointer to a pointer to a vtable) allows for vtable sharing among multiple instances of the same object class. On a system with hundreds of object instances, vtable sharing can reduce memory requirements considerably. All COM objects inherit from IUmknown |
From: Oscar F. <of...@wa...> - 2004-07-27 22:04:30
|
"Victor Romanov" <vi...@ua...> writes: > From MSDN: > For any given platform (hardware and operating system combination), COM > defines a standard way to lay out virtual function tables (vtables) in > memory, and a standard way to call functions through the vtables. Thus, any > language that can call functions via pointers (C, C++, Small TalkR, Ada, and > even Basic) all can be used to write components that can interoperate with > other components written to the same binary standard. The double indirection > (the client holds a pointer to a pointer to a vtable) allows for vtable > sharing among multiple instances of the same object class. On a system with > hundreds of object instances, vtable sharing can reduce memory requirements > considerably. You are confusing MS COM terminology with C++ compiler terminology. The vtable and inheritance implementation for a given C++ compiler does not need to match that of COM. Furthermore, there are other details involved (register usage, for instance, as mentioned earlier on this thread). Actually, there is nothing on the C++ standard that mandates an vtable. > All COM objects inherit from IUmknown Deriving your classes from IUnknown doesn't help. If your C++ compiler implementation (i.e. g++) is not 100% compatible with the COM specification, you need to use a C-ish approach. Of course, MSVC++ is compatible with the COM specification simply because COM was created to comply with the MSVC++ ABI, AFAIK. -- Oscar |
From: Michael G. <mg...@te...> - 2004-07-27 20:42:31
|
> To help you with your problem: > You can still write the majority of your code using C++, classes > etc. (try to avoid exceptions). But you'll have to provide proxy > functions that can be called from C if you wish to mix compilers. Here is a simple example what I mean by 'proxy function' A.hpp =2D*- snip -*- snip -*- snip -*- snip -*- snip -*- snip -*- snip -*- class A { public: A() {_a=3D0;} long getA() {return _a;} void setA(long l) {_a=3Dl;} private: long _a; } =2D*- snip -*- snip -*- snip -*- snip -*- snip -*- snip -*- snip -*- Aproxy.cpp =2D*- snip -*- snip -*- snip -*- snip -*- snip -*- snip -*- snip -*- #define MY_CLASS_A_DLL include "Aproxy.h" __declspec(dllexport) AHANDLE ACreate() { return new A(); } __declspec(dllexport) long AGetMemberA(AHANDLE aParm) { A* a =3D (A*)aParm; return a->getA(); } __declspec(dllexport) void ACreate(AHANDLE a, long l) { A* a =3D (A*)aParm; a->setA(l); return; } typedef LHANDLE AHANDLE; #ifdef __cpluspls extern "C" { #endif // declare all proxy functions, e.g. AHANDLE ACreate(); long AGetMemberA(AHANDLE ahnd); #ifdef __cpluspls } #endif #undef IMPORTAPI =2D*- snip -*- snip -*- snip -*- snip -*- snip -*- snip -*- snip -*- Aproxy.h =2D*- snip -*- snip -*- snip -*- snip -*- snip -*- snip -*- snip -*- #ifdef MY_CLASS_A_DLL #define IMPORTAPI __declspec(dllexport) #else #define IMPORTAPI __declspec(dllimport) #endif typedef LHANDLE AHANDLE; #ifdef __cpluspls extern "C" { #endif // declare all proxy functions, e.g. // (omit APIENTRY if you don't need it) IMPORTAPI APIENTRY AHANDLE ACreate(); IMPORTAPI APIENTRY long AGetMemberA(AHANDLE ahnd); IMPORTAPI APIENTRY long ASetMemberA(AHANDLE ahnd, long l); #ifdef __cpluspls } #endif #undef IMPORTAPI =2D*- snip -*- snip -*- snip -*- snip -*- snip -*- snip -*- snip -*- There are missing a few wistles and bells but I hope you get the idea. Best, Michael =2D-=20 Vote against SPAM - see http://www.politik-digital.de/spam/ Michael Gerdau email: mg...@te... GPG-keys available on request or at public keyserver |
From: Luke D. <cod...@ho...> - 2004-07-28 02:08:41
|
With respect to everyone else who replied to this thread, I think they are incorrect in this instance. I agree with you that MinGW GCC and MSVC should be compatible enough to allow COM method calls, and indeed they are as evident from DirectX programs and other COM client applications written using MinGW. It's not immediately obvious to me from the COM documentation but if you look in the MinGW header files you will find that COM methods (e.g. those of IUnknown) are declared as stdcall, and by changing your declarations in the DLL to the following, it works for me: class CUnk : public IUnknown { public: virtual HRESULT __stdcall QueryInterface(REFIID iid, void ** ppvObject); virtual ULONG __stdcall AddRef(void); virtual ULONG __stdcall Release(void); }; I am not familiar enough with COM server programming to know whether this requirement to specify __stdcall is the same as MSVC or whether it should be implied by the base class, but intuitively I think GCC should at least issue a warning when a virtual function is overridden with a different calling convention. Luke ----- Original Message ----- From: "Victor Romanov" <vi...@ua...> To: <min...@li...> Sent: Tuesday, July 27, 2004 6:48 PM Subject: [Mingw-users] MinGW, MSVC7 > I have one problem. I hope somebody help me. > I install MinGW-3.1.0-1.exe ? minimalist. > I wrote this simple code: > > #include <comcat.h> > #include <stdio.h> > #include "dllfct.h" > > class CUnk : public IUnknown > { > public: > virtual HRESULT QueryInterface(REFIID iid, void ** ppvObject); virtual > ULONG AddRef(void); virtual ULONG Release(void); }; > > HRESULT CUnk::QueryInterface(REFIID iid, void ** ppvObject) { return 0; } > > ULONG CUnk::AddRef(void) > { > printf("AddRef\n"); > return 0; > } > > ULONG CUnk::Release(void) > { > printf("Release\n"); > return 0; > } > > extern "C" __declspec(dllexport) void *tstfunc () { CUnk *p = new CUnk; > return p; } > > Compile with commands: > g++ -c -DBUILD_DLL dllfct.cpp > dllwrap --output-lib=libtstdll.a --dllname=hello.dll --driver-name=g++ > dllfct.o > > I receive library hello.dll. > > Next step I wrote code to call my library: > IUnknown *pClass = (IUnknown *)tstfunc(); > pClass->AddRef(); > pClass->Release(); > > All working Ok. > > I wrote the same code in MSVC7: > typedef void *(*FUNCTION_PTR)(); > HMODULE h = LoadLibrary("hello.dll"); > FUNCTION_PTR tstfunc; > tstfunc = (FUNCTION_PTR)GetProcAddress(h, "tstfunc"); IUnknown *pClass = > (IUnknown *)tstfunc(); > pClass->AddRef(); > pClass->Release(); > FreeLibrary(h); > > > But if I call my MINGW library from MSVC7 I receive run time error at line > pClass->AddRef(); The function is called(I see ?AddRef ? string in my > console). Error is ?Run-Time Check Failure #0. The value of ESP was not > property saved across a function call. This is usually a result of calling a > function declared with one calling conversion with a function pointer declared > with different calling conversion.? > > ---- > http://photo.alkar.net/ |
From: Danny S. <dan...@cl...> - 2004-07-28 08:43:15
|
----- Original Message ----- From: "Luke Dunstan" | With respect to everyone else who replied to this thread, I think they are | incorrect in this instance. I agree with you that MinGW GCC and MSVC should | be compatible enough to allow COM method calls, and indeed they are as | evident from DirectX programs and other COM client applications written | using MinGW. It's not immediately obvious to me from the COM documentation | but if you look in the MinGW header files you will find that COM methods | (e.g. those of IUnknown) are declared as stdcall, and by changing your | declarations in the DLL to the following, it works for me: | | class CUnk : public IUnknown | { | public: | virtual HRESULT __stdcall QueryInterface(REFIID iid, void ** | ppvObject); | virtual ULONG __stdcall AddRef(void); | virtual ULONG __stdcall Release(void); | }; | | I am not familiar enough with COM server programming to know whether this | requirement to specify __stdcall is the same as MSVC or whether it should be | implied by the base class, but intuitively I think GCC should at least issue | a warning when a virtual function is overridden with a different calling | convention. FYI, this bug has been reported to GCC http://gcc.gnu.org/bugzilla/show_bug.cgi?id=14688 It has been around since 2.95 days. Danny | | Luke | | ----- Original Message ----- | From: "Victor Romanov" <vi...@ua...> | To: <min...@li...> | Sent: Tuesday, July 27, 2004 6:48 PM | Subject: [Mingw-users] MinGW, MSVC7 | | | > I have one problem. I hope somebody help me. | > I install MinGW-3.1.0-1.exe ? minimalist. | > I wrote this simple code: | > | > #include <comcat.h> | > #include <stdio.h> | > #include "dllfct.h" | > | > class CUnk : public IUnknown | > { | > public: | > virtual HRESULT QueryInterface(REFIID iid, void ** ppvObject); virtual | > ULONG AddRef(void); virtual ULONG Release(void); }; | > | > HRESULT CUnk::QueryInterface(REFIID iid, void ** ppvObject) { return 0; } | > | > ULONG CUnk::AddRef(void) | > { | > printf("AddRef\n"); | > return 0; | > } | > | > ULONG CUnk::Release(void) | > { | > printf("Release\n"); | > return 0; | > } | > | > extern "C" __declspec(dllexport) void *tstfunc () { CUnk *p = new CUnk; | > return p; } | > | > Compile with commands: | > g++ -c -DBUILD_DLL dllfct.cpp | > dllwrap --output-lib=libtstdll.a --dllname=hello.dll --driver-name=g++ | > dllfct.o | > | > I receive library hello.dll. | > | > Next step I wrote code to call my library: | > IUnknown *pClass = (IUnknown *)tstfunc(); | > pClass->AddRef(); | > pClass->Release(); | > | > All working Ok. | > | > I wrote the same code in MSVC7: | > typedef void *(*FUNCTION_PTR)(); | > HMODULE h = LoadLibrary("hello.dll"); | > FUNCTION_PTR tstfunc; | > tstfunc = (FUNCTION_PTR)GetProcAddress(h, "tstfunc"); IUnknown *pClass = | > (IUnknown *)tstfunc(); | > pClass->AddRef(); | > pClass->Release(); | > FreeLibrary(h); | > | > | > But if I call my MINGW library from MSVC7 I receive run time error at line | > pClass->AddRef(); The function is called(I see ?AddRef ? string in my | > console). Error is ?Run-Time Check Failure #0. The value of ESP was not | > property saved across a function call. This is usually a result of calling | a | > function declared with one calling conversion with a function pointer | declared | > with different calling conversion.? | > | > ---- | > http://photo.alkar.net/ | | | ------------------------------------------------------- | This SF.Net email is sponsored by BEA Weblogic Workshop | FREE Java Enterprise J2EE developer tools! | Get your free copy of BEA WebLogic Workshop 8.1 today. | http://ads.osdn.com/?ad_id=4721&alloc_id=10040&op=click | _______________________________________________ | MinGW-users mailing list | Min...@li... | | You may change your MinGW Account Options or unsubscribe at: | https://lists.sourceforge.net/lists/listinfo/mingw-users |
From: Victor R. <vi...@ua...> - 2004-07-28 09:03:46
|
I declare my classes like IUnknown(using STDMETHOD). All working. Thank for all. ---- http://photo.alkar.net/ |