How to make serial dll binaries in VS versions?

For example, winsock libs works fine in all versions of the visual studio. But I am having real problems to ensure consistent binary coding in all versions. A DLL compiled using VS 2005 will not work when connected to an application written in 2008. I upgraded both 2k5 and 2k8 to SP1, but the results have not changed much. It works, which is good. But when they enable this using a C # application, the C # application gets access violation errors, but it works fine with a classic C ++ application.

Is there a strategy I need to know when I provide dll?

+6
c ++ dll
Oct 24 '08 at 9:28
source share
3 answers

First, do not run anything other than plain old data across the boundaries of a DLL. those. structures are accurate. there are no classes. Secondly, make sure that ownership is not transferred, i.e. Any structures passed along the dll boundary are never freed outside the dll. Thus, if you dll export the X * GetX () function, there is a corresponding function of the FreeX (X *) type, which ensures that the same runtime is responsible for de-distribution.

Further. Get your dll files for linking with static runtime. Combining a project involving dls from several third parties, each of which is associated with waiting for different versions that are potentially different from what the application expects, is a pain that potentially forces the installer software to set runtimes for 7.0, 7.1, 8.0, and 9.0 - some of which exist in different service packs that may or may not cause problems. Kindly - statically link your dll projects.

- Edit: You cannot directly export a C ++ class using this approach. Sharing class definitions between modules means that you MUST have a uniform runtime, since different compilers or versions of compilers will generate decoded names in different ways.

You can get around this limitation by exporting your class instead as a COM-style interface ... that is, while you cannot export the class offline, you can export the “interface”, which you can easily make by class declarations containing only pure virtual functions ...

struct IExportedMethods { virtual long __stdcall AMethod(void)=0; }; // with the win32 macros: interface IExportedMethods { STDMETHOD_(long,AMethod)(THIS)PURE; }; 

In the definition of your class, you inherit this interface:

  class CMyObject: public IExportedMethods { ... 

You can export such interfaces using the C factory methods:

  extern "C" __declspec(dllexport) IExportedClass* WINAPI CreateMyExportedObject(){ return new CMyObject; } 

This is a very easy way to export compiler versions and independent runtime class versions. Please note that you still cannot delete one of them. You must enable the release function as a member of a DLL or interface. As a member of an interface, it might look like this:

  interface IExportedMethods { STDMETHOD_(void) Release(THIS) PURE; }; class CMyObject : public IExportedMethods { STDMETHODIMP_(void) Release(){ delete this; } }; 

You can use this idea and continue with it - inherit your interface from IUnknown, implement the ref counted AddRef and Release methods, as well as the ability to use QueryInterface for v2 interfaces or other functions. And finally, use DllCreateClassObject as a means to create your object and obtain the necessary COM registration. None of this is necessary, but you can easily get rid of the simple interface definition available through the C function.

+10
Oct 24 '08 at 9:56
source share

I disagree with Chris Becke's point of view, seeing the benefits of his approach.

The disadvantage is that you cannot create libraries of utility objects because you are forbidden to share them through libraries.

Chris Solution Extension

How to make serial dll binaries in VS versions?

Your choice depends on how different the compilers are. On the one hand, different versions of the same compiler can handle data alignment in the same way, and thus you can identify structures and classes in your DLLs. On the other hand, you may not trust other library compilers or compilation options.

In the Windows Win32 API, they dealt with the problem through "handlers". You do the same:

1 - Never expose the structure. Print only pointers (i.e. void * pointer)
2 - Access to the structure data is carried out through functions , indicating the pointer as the first parameter
3 - this allocation / deletion data struct pointer is used through functions

This way you can avoid recompiling everything when your structure changes.

C ++ way to do this is PImpl. See http://en.wikipedia.org/wiki/Opaque_pointer

It has the same behavior as the void * concept, but with PImpl you can use both RAII and encapsulation, as well as the benefits of strong security. To do this, you need a compatible design (the same compiler), but not the same runtime or version (if the scenery is the same between versions).

Another solution?

Hoping to combine DLLs from different versions of compilers / compilers is either a recipe for disaster (as you explained in your question), or tedious, since you let go of most (if not all) C ++ solutions so that your code returns to basic C- encoding or both.

My decision:

1 - Make sure all your modules are compiled using the same compiler / version . Period.
2 - Make sure all your modules are compiled dynamically with the same runtime
3 - Make sure that you have an “encapsulation” of all third-party modules that you have no control over (it is impossible to compile with your compiler), as Chris Beck rightly explained in How to make serial DLL binaries for VS versions? .

Note that it is not surprising and not outrageous to claim that all modules of your application are compiled against the same compiler and the same version of the compiler.

Do not let anyone say that you mix compilers - that’s good. Is not. The freedom to mix the compiler for most people is the same freedom that you can enjoy jumping from the top of the building: you are free to do it, but usually you just don't need it.

My solution allows you to:

1 - export classes and, thus, create real, non-castrated, C ++ libraries (as you were supposed to do with Visual C ++ __declspec (dllexport), for example)
2 - assignment of the distribution of the transmission (what happens without your consent when using the allocation and / or release of the embedded code or STL)
3 - you should not annoy the problems associated with the fact that each module has its own version of the runtime (i.e., memory allocation and some global data used by the C or C ++ API)

Please note that this means that you should not mix the debug version of your modules with the release versions of other modules. Your application is completely debugged or completely freed.

+5
Oct 24 '08 at 10:40
source share

regarding the issue of passing structure, this thing is safe if you align your structure, for example:

 #pragma pack(push,4) typedef myStruct { int a; char b; float c; }myStruct; #pragma pack(pop)
#pragma pack(push,4) typedef myStruct { int a; char b; float c; }myStruct; #pragma pack(pop) 

You can put this ad in the header file and include it in both projects. This way you will not have problems transferring structures.

Also, make sure that you link statically with runtime libraries and are not trying to perform a task such as allocating memory (ptr = malloc (1024)) in a module, and then freeing that memory in another module (free (ptr)) .

+2
Oct 24 '08 at 11:48
source share



All Articles