Solved

Limited types in C++ DLLs

Posted on 2008-06-21
18
585 Views
Last Modified: 2013-12-14
I have started using a combination of C# and C++ DLLs (VC6) for running the computational part of my image processing tasks in C#. As it is very easy to use C++ DLLs in C# using DLLImport, I have run into a problem. It appears to me that only a limited number of types can be used in the creation of this DLL.

I start by opening the VC6 wizard and choose the Win32 DLL project. From there, I next choose the third option of a simple DLL with some exported symbols.

What I am trying to do is to try to use the string type. I have created a very simple function that returns a string of characters. My function is below:
extern "C" __declspec(dllexport) char* testStr(void);

When I use char* in the prototype, the code compiles with no problem. Next I try
extern "C++" __declspec(dllexport) char* testStr(void);

Also no problem. Next I try
extern "C" __declspec(dllexport) string  testStr(void);

I get a compilation error. Same if I do
extern "C++" __declspec(dllexport) string  testStr(void);

I have included all the headers in the declarations
#include <string>
#include <string.h>
#include "string.h"

but I still get the compiling error. Is there a way around this? I can work with the char* approach if required but I would prefer to use string and have the same/similar types in the unmanaged and managed part of my code. Is there a simple reason for this compiling error?

Can someone post the correct syntax of how this should be done?

Thanks
0
Comment
Question by:aaborkar
  • 8
  • 5
  • 4
18 Comments
 
LVL 40

Accepted Solution

by:
evilrix earned 125 total points
ID: 21840065
>> extern "C" __declspec(dllexport) string  testStr(void);
The string class is a C++ object, when you use extern "C" you are explicitly saying this code is C only. This being the case, it cannot support the use of string.

>> extern "C++" __declspec(dllexport) string  testStr(void);
You either need a "using namespace std;" before the declaration or you need to use the fully qualified name (std::string). See below. Why do you need to use extern "C++" if the code is already C++?

#include <string>
 

extern "C++"

{

	__declspec(dllexport) std::string  testStr(void);

}

Open in new window

0
 
LVL 19

Expert Comment

by:mrwad99
ID: 21840366
Greetings!

Not wishing to call my friend Rx wrong, can I just comment on

>> "when you use extern "C" you are explicitly saying this code is C only."

Strictly speaking that is not true: let me quote from a good site I have used:

"Defining a C++ function as extern "C", tells the compiler to generate function names and function calls that are compatible with the old "C" standard. This way a C program can call C++ programs and the other way round."

http://www.cs.tau.ac.il/~angela/RobotsBattleSrc/cprog.htm
0
 
LVL 40

Expert Comment

by:evilrix
ID: 21840887
Hi mrwad99. Thanks for your augmentation. My response was specifically trying not to be too technical and; rather, just convey the salient point that this gives the function C semantics. The point is that the result of trying to use a non-POD (plain of data) type in a function with C linkage is undefined. A std::string is not a POD type and is not part of the C langauge.

" 7.5 Linkage specifications

9. Linkage from C++ to objects defined in other languages and to objects defined in C + + from other languages
is implementation-defined and language-dependent. Only where the object layout strategies of two language
implementations are similar enough can such linkage be achieved."

C is different language from C++.
0
 

Author Comment

by:aaborkar
ID: 21840980
Thanks for your response guys. The compilation works fine now. I had completely forgotten about the std namespace. I thought std was only used when cin and cout were used but I guess I was wrong.
0
 
LVL 40

Expert Comment

by:evilrix
ID: 21841364
All STL entities are in the std namespace :)
0
 

Author Comment

by:aaborkar
ID: 21846131
Now the code compiles. But I have to specify the linkage as C++ and not C. If I try to compile the code as

extern "C" __declspec(dllexport) std::string inStr(void); I get the following below.

No warning if I do
extern "C++" __declspec(dllexport) std::string inStr(void); I get the following below.


Now the problems seems to be that C# cannot find entry points into a dll that has C++ linkage. But I will post this on a separate thread.
Compiling...

DLLFile.cpp

.\DLLFile.cpp(4) : warning C4190: 'inStr' has C-linkage specified, but returns UDT 'std::basic_string<_Elem,_Traits,_Ax>' which is incompatible with C

        with

        [

            _Elem=char,

            _Traits=std::char_traits<char>,

            _Ax=std::allocator<char>

        ]

Linking...

Open in new window

0
 
LVL 40

Expert Comment

by:evilrix
ID: 21846191
Did you see my point above? The std::string is not a C type so trying to use it in a function that has C linkage is not portable. The reason C# can't see the functions with C++ linkage is that the ABI (Application Binary Interface) for C++ defines no standard for name mangling (the mechanism that allows you to have overloaded functions); hence you normally have to specify C linkage. The problem, as you have discovered, is that by doing so you hinder your ability to use C++ types at the API boundary. There is no easy way to get around this I'm afraid.

http://en.wikipedia.org/wiki/Application_binary_interface
http://en.wikipedia.org/wiki/Name_mangling
0
 
LVL 19

Expert Comment

by:mrwad99
ID: 21854312
I was just writing up my findings of a past question I asked about passing STL object across DLL boundaries, and released that you are the same thing here, so I thought I would comment again on this.

Something I came across (and that Rx will be familiar with) is that

***you cannot safely pass STL objects across DLL boundaries. ***

You are returning a std::string from a DLL, presumably for use in a C# app/DLL.

You are asking for a major headache IMHO when you start using this code (believe me, I have been there :))

Just pass plain memory (char*) and then construct some helper object (eg std::string maybe) with the memory passed when it is received.

I found this article whilst searching: it talks about a std::map, but the point it raises about Microsoft's dodgy, sorry, "feature-rich", implementation of the STL is interesting:

http://www.flipcode.com/archives/Using_stdmap_Across_DLL_Boundaries.shtml

An alternative to the STL is also mentioned.

You can search Google or similar for the words STL DLL boundary to find more reasons to not to do what you are doing if you like :)
0
Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

 
LVL 40

Expert Comment

by:evilrix
ID: 21854341
>> Just pass plain memory (char*) and then construct some helper object (eg std::string maybe) with the memory passed when it is received.

Just one observation. Be careful, if it's gone out of scope when it's return from the function you'll also be in hot water :) If it's not then I'd question how you're persisting it. Static type? Heap? Pass in buffer? Each has it's own potential pitfalls.
0
 

Author Comment

by:aaborkar
ID: 21855689
Well I was able to do some searching and found that the StringBuilder class in C# helps solve this issue.  StringBuilder can be used with a fixed buffer size and passed over to C++ in the form of char*. Then a simple strcpy(...) {within the buffer size} works to modify the string.

Now my next worry is to figure out how to send classes and structs from C# to C++. I have started a new thread:
http://www.experts-exchange.com/Microsoft/Development/.NET/Visual_CPP/Q_23508420.html

since I don't want to deviate away from the current subject. Thanks for all the help guys.
 

0
 
LVL 19

Expert Comment

by:mrwad99
ID: 21855891
aaborkar:

I see you are new to EE, so if you feel this question has been answered, please close it by accepting the answer/s you feel best solved the problem for you.  This prevents community support getting annoyed at having to clean up after users :)
0
 
LVL 40

Expert Comment

by:evilrix
ID: 21855934
BTW: mrwad99, I forgot to say it's good to see you getting stuck in there and helping out :) Nice to have you on-board as a regular expert... I'm looking forward to sharing some threads with you my friend ;)
0
 
LVL 19

Expert Comment

by:mrwad99
ID: 21855976
:o) @ RX

Heh, I am afraid at the minute I just want to keep my premium services for free; I do a lot more asking than I do answering as you know!  But I did wamt to share what I had myself learnt with your help on the previous thread here, as I found it a real pain, and the source of many many cold sweats until I had a reasonable explanation as to why it was happening.  This will hopefully prevent others having that, just like many PAQs here have saved me :)
0
 
LVL 40

Expert Comment

by:evilrix
ID: 21855995
>> I do a lot more asking than I do answering as you know!
Every little helps though :)

Take care my friend.

-Rx.
0
 
LVL 19

Expert Comment

by:mrwad99
ID: 21856008
Ditto :)
0
 
LVL 40

Expert Comment

by:evilrix
ID: 21857901
I feel I should point out that I'd already correctly answered the question you asked well before the answer that was selected (the very first answer in fact identifies the problem and the solution) here and whilst I don't want to take anything away from mrwad99, the first correct answer posted should be the one accepted. If any additional posts assisted you should then split the points accordingly. Is there any reason you chose to ignore the answers I provided?
0
 

Author Closing Comment

by:aaborkar
ID: 31469477
Sorry, I was absent minded when I chose my previous answer. How do I distribute additional points to other providers?
0

Featured Post

What Is Threat Intelligence?

Threat intelligence is often discussed, but rarely understood. Starting with a precise definition, along with clear business goals, is essential.

Join & Write a Comment

Introduction This article is a continuation of the C/C++ Visual Studio Express debugger series. Part 1 provided a quick start guide in using the debugger. Part 2 focused on additional topics in breakpoints. As your assignments become a little more …
Here is a helpful source code for C++ Builder programmers that allows you to manage and manipulate HTML content from C++ code, while also handling HTML events like onclick, onmouseover, ... Some objects defined and used in this source include: …
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…

747 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now