From: Branimir Maksimovic on
Paul Bibbings wrote:
> Let us say that we have a shared library, implemented in MSVC, that
> exposes the following interface (pseudocode):
>
> // shared_lib_export.h
> extern "C" {
> __declspec(dllexport) std::ostream* __cdecl
> GetNewStream(); // dynamically allocated
> __declspec(dllexport) void __cdecl
> PrintToStream(std::ostream*, const char *);
> __declspec(dllexport) void __cdecl
> FreeStream(std::ostream*); // deallocated
> }
>
> Then, in an application built using another implementation, say GNU gcc,
> suppose I want to do something like:
>
> #include <ostream>
> #include "shared_lib_import.h"
>
> int main()
> {
> std::ostream* os = GetNewStream();
> PrintToStream(os, "Is this valid/safe/insane?\n");
> FreeStream(os);
>
> return 0;
> }
>

I don;t think this can work. std::ostream from gcc, and std::ostream
from vc are two different classes and possibly have completely different
layout.
You have to use COM , which is well defined (vtable layout and data
parameters).

Greets

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: George Neuner on
On Tue, 16 Feb 2010 13:19:19 CST, "Martin B." <0xCDCDCDCD(a)gmx.at>
wrote:

>
>void* and RTTI don't mix.
>What might make sense is have a library header that declares a
>struct ostream_handle;
>and then the library only exposes pointers to this undefined type.
>

Because this thread involves MSVC I was actually thinking about using
MFC RUNTIME_CLASS information rather than standard C++ RTTI.
RUNTIME_CLASS works with void* and I have used it in situations
similar to the one in this thread.

You'd have to wrap standard classes to use it, but the mechanism is
already there and reasonably simple to use.

George

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: George Neuner on
On Mon, 15 Feb 2010 16:42:54 CST, Maxim Yegorushkin
<maxim.yegorushkin(a)gmail.com> wrote:

>On 15/02/10 04:55, Paul Bibbings wrote:
>> Specifically, I'm thinking here about passing pointers to standard
>> library objects across implementation boundaries (and, indeed, across
>> DLL boundaries).
>>
>> Let us say that we have a shared library, implemented in MSVC, that
>> exposes the following interface (pseudocode):
>>
>> // shared_lib_export.h
>> extern "C" {
>> __declspec(dllexport) std::ostream* __cdecl
>> GetNewStream(); // dynamically allocated
>> __declspec(dllexport) void __cdecl
>> PrintToStream(std::ostream*, const char *);
>> __declspec(dllexport) void __cdecl
>> FreeStream(std::ostream*); // deallocated
>> }
>>
>> Then, in an application built using another implementation, say GNU gcc,
>> suppose I want to do something like:
>>
>> #include<ostream>
>> #include "shared_lib_import.h"
>>
>> int main()
>> {
>> std::ostream* os = GetNewStream();
>> PrintToStream(os, "Is this valid/safe/insane?\n");
>> FreeStream(os);
>>
>> return 0;
>> }
>>
>> What can we say about the validity of obtaining, storing and passing
>> back for use a pointer in this way?
>
>It won't work because MSVC and gcc have different standard libraries.
>MSVC std::ostream has one declaration, gcc std::ostream has another and
>they are not compatible.
>
>It will work with the same C++ compiler though.

It _might_ work in the example because the GCC code is seeing just a
pointer - not an object - and the object is being manipulated only by
library code.

You are correct, though, that it will fail if the pointer is used
directly to access the standard object. It would be safer for the
library to return a void* that the application can use only as an
identifier ... but then that requires RTTI to ensure safety in the
library and that may cause problems too.


>> In short, can such a use ever be viable, and if so, under what
>> circumstances?
>
>Not in C++. You would need to wrap your API in C to make it truly portable.

Yes. Both MSVC and GCC can export classes from DLLs, but their
different name-mangling schemes prevents cross platform use, and even
if you solve that I don't know if their object representations and
dispatch methods are compatible.

George

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: George Neuner on
On Sun, 14 Feb 2010 22:55:16 CST, Paul Bibbings
<paul.bibbings(a)gmail.com> wrote:

>Specifically, I'm thinking here about passing pointers to standard
>library objects across implementation boundaries (and, indeed, across
>DLL boundaries).
>
>Let us say that we have a shared library, implemented in MSVC, that
>exposes the following interface (pseudocode):
>
> // shared_lib_export.h
> extern "C" {
> __declspec(dllexport) std::ostream* __cdecl
> GetNewStream(); // dynamically allocated
> __declspec(dllexport) void __cdecl
> PrintToStream(std::ostream*, const char *);
> __declspec(dllexport) void __cdecl
> FreeStream(std::ostream*); // deallocated
> }
>
>Then, in an application built using another implementation, say GNU gcc,
>suppose I want to do something like:
>
> #include <ostream>
> #include "shared_lib_import.h"
>
> int main()
> {
> std::ostream* os = GetNewStream();
> PrintToStream(os, "Is this valid/safe/insane?\n");
> FreeStream(os);
>
> return 0;
> }
>
>What can we say about the validity of obtaining, storing and passing
>back for use a pointer in this way? Can this ever be well-defined, and
>what are the minimal guarantees that we must require for it to be so
>(not to mention passing across the C-style string)?
>
>For instance, I'm guessing that the size of a pointer in both
>implementations would need to be the same. Also, we have to allow the
>shared library code to manage the destruction of the object pointed to,
>ensuring its valid lifetime by a properly-balanced use of GetNewStream()
>and FreeStream(...). More importantly, we would have to forget about
>any attempts to use the object in our calling code, in the sense of
>dereferencing the pointer.
>
>In short, can such a use ever be viable, and if so, under what
>circumstances? Does the standard have anything to say to help me here?
>
>Regards
>
>Paul Bibbings

The standard says nothing whatsoever about sharable libraries. The
best that can be said is "it might work". It depends on the size of
pointers, the type of MS DLL (regular or MFC extension), and on
whether the particular versions of MSVC and GCC have compatible object
structures and dispatch methods (AFAIK, all Windows compilers use SEH
for exception handling).

MS regular DLLs present a "C" interface, regardless of the language
used to write them. COM/ATL DLLs are a version of regular DLLs.
Regular DLLs have a private heap from which they normally make all
allocations. There is a way to change the DLL's default heap (which
is used by MFC extension DLLs to allocate from the application heap)
but offhand I don't recall how to do it. I haven't looked into this
for quite a while, but it used to be (circa C++ v5-v7) that trying to
directly access DLL private heap objects from the application caused a
protection fault.

Extension DLLs have a nice C++ friendly interface, but they are a
whole different matter and I doubt that GCC can cope with them. I
don't know of anyone that has ever tried.

As far as your example goes, exposing a functional API and using the
object pointer/reference simply as an identifier is the safest way to
deal with DLL objects. I just don't know whether it will work across
platforms.

George

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Martin B. on
George Neuner wrote:
> On Mon, 15 Feb 2010 16:42:54 CST, Maxim Yegorushkin
> <maxim.yegorushkin(a)gmail.com> wrote:
>
>> On 15/02/10 04:55, Paul Bibbings wrote:
>>> Specifically, I'm thinking here about passing pointers to standard
>>> library objects across implementation boundaries (and, indeed, across
>>> DLL boundaries).
>>>
>>> (....)
>>>
>>> What can we say about the validity of obtaining, storing and passing
>>> back for use a pointer in this way?
>> It won't work because MSVC and gcc have different standard libraries.
>> MSVC std::ostream has one declaration, gcc std::ostream has another and
>> they are not compatible.
>>
>> It will work with the same C++ compiler though.
>
> It _might_ work in the example because the GCC code is seeing just a
> pointer - not an object - and the object is being manipulated only by
> library code.
>
> You are correct, though, that it will fail if the pointer is used
> directly to access the standard object. It would be safer for the
> library to return a void* that the application can use only as an
> identifier ... but then that requires RTTI to ensure safety in the
> library and that may cause problems too.
>

void* and RTTI don't mix.
What might make sense is have a library header that declares a
struct ostream_handle;
and then the library only exposes pointers to this undefined type.

br,
Martin

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]