C++/CLI managed wrapper around C static library - c++-cli

Help!
I'm totally exhausted/frustrated with what seems to be a reasonably easy task. I’m not sure what I'm doing wrong; let alone if I'm doing it correct. I'm "required" to use an existing library (a C static library – over 100,000 lines of straight C code) in developing a WPF application (VS 2010, C# 4.0). Oh, and I can't touch the existing C code - use it as is!
I've read so many postings (advanced topics, how-to, etc), yet I'm so new to C++/CLI that it's just not making sense. From what I've read the best approach is to wrap the C static library as follows:
Unmanaged C static library <---> C++/CLI managed wrapper DLL <--->
managed WPF application
This is the stripped down C header file:
/* Call this function to execute a command. */
int issue_command(int command, long param1, long param2);
/* Completion call back function; you must supply a definition. */
extern int command_completed(int command, long param1, long param2);
struct struct_command_str
{
char command_str[10];
char param1_st[2];
char param2_st[2];
char success;
};
/* You must supply definitions to the following extern items. */
extern int command_status;
extern struct struct_command_str command_str;
The problem(s):
What I can’t seem to do correctly is provide a C++/CLI implementation for the call back functions, and the two extern items (command_status and struct command_str).
Can someone provide a sample C++/CLI implementation for the above missing call back functions and externs?
Thanks in advance for your assistance.

in your C++/CLI managed wrapper project, add 2 files :
a .c file :
extern void doSomething();
int command_status = 0;
struct_command_str command_str = { "command1", "p1", "p2", 't' };
int command_completed(int command, long param1, long param2) {
...
command_status = 1;
...
doSomething();
...
command_status = 2;
...
return 3;
}
a cpp file
void doSomethingManagedWrapper() {
...
call managed code
...
}
void doSomething() {
doSomethingManagedWrapper();
}

when you implement these in your c++/cli module, use the same signature shown in the c header file,but prefixed with extern "C".
also put an extern "C" block around the #include of the C header file.

Related

I am about to use dlopen() to open shared object. Do I need to include corresponding headers if shared object?

I have to use dlopen() and access functions from shared object in my code. Do I need to include headers of corresponding functions of shared object ?
Because of the way dlopen() and dlsym() operate, I don't see how that would accomplish anything. Very roughly speaking, dlopen() copies the library binary into your program space and adds the addresses of its exported symbols (i.e. global functions & variables) to your program's symbol table.
Because the library was not linked to your program at compile-time, there's no way your code could possibly know the instruction addresses of these new functions tacked on at run-time. The only way to access a run-time dynamically linked symbol is via a pointer obtained from dlsym().
You have to create a function pointer for each and every library definition that you want to use. If you want to call them like regular functions, in C-language you can manually typedef type definitions for the function pointers, specifying their parameters and return values, then you can call the pointers just like regular functions. But note that you have to define all of these manually. Including the library header doesn't help.
In C++ I think there are issues with storing dlsym() output in a typedef'd pointer due to stricter standards, but this should work in C:
addlib.c (libaddlib.dylib):
int add(int x, int y) {
return x+y;
}
myprogram.c:
#include <stdio.h>
#include <dlfcn.h>
typedef int (*add_t)(int, int);
int main() {
void *lib_handle;
add_t add; // call this anything you want...it's a pointer, it doesn't care
lib_handle = dlopen("libaddlib.dylib", RTLD_NOW);
if (lib_handle == NULL) {
// error handling
}
add = (add_t)dlsym(lib_handle, "add");
if (add == NULL) {
// error handling
}
printf("Sum is %d\n", add(17, 23));
dlclose(lib_handle); // remove library from address space
return 0;
}
(Update: I compiled the dylib and myprogram...it works as expected.)

Working with structures in C++/CLI

I have following code
ref class A
{
typedef ref struct All
{
std::string x;
}All_t;
};
in my program I am using it in following manner
A::All_t t;
t.X = "H";
This declaration throwing error as
error C4368: cannot define 'x' as a member of managed 'A::All': mixed types are not supported
I understand that I am declaring native varible inside managed code which is not allowed but now I would like to know changes I will need to make to make my structure suitable to managed project.
Thanks.
I'm assuming you originally had std::string x; not std::string *x (since using the pointer to string does not generate that error). You are not allowed to directly embed a native type in a managed type, but you are allowed to indirectly have one (via a pointer) See:
http://msdn.microsoft.com/en-us/library/xhfb39es(v=vs.80).aspx
After I fixed the compiler errors in your sample, it builds without error:
#include "stdafx.h"
#include <string>
using namespace System;
ref class A
{
public:
typedef ref struct All
{
std::string * x;
}All_t;
};
int main(array<System::String ^> ^args)
{
A::All_t t;
t.x = new std::string("H");
return 0;
}

Dumpbin shows strange method name (generating exporting function in MS Visual C++)

I have created new Win32 project in my VS and have selected Dynamic Library ( *.dll ) for this aim.
I have defined some exporting function in the main file:
__declspec(dllexport)
int TestCall(void)
{
int value = 4 / 2;
std::cout << typeid(value).name() << std::endl;
return value;
}
__declspec(dllexport)
void SwapMe(int *first, int *second)
{
int tmp = *first;
*first = *second;
*second = tmp;
}
When I've looked at the dumpin /exports, I've got:
ordinal hint RVA name
1 0 00001010 ?SwapMe##YAXPEAH0#Z
2 1 00001270 ?TestCall##YAHXZ
I'm calling in the C# version like this:
[DllImport(#"lib1.dll", EntryPoint = "?TestCall##YAHXZ",
CallingConvention = CallingConvention.Cdecl)]
static extern int TestCall();
It's not the correct form of using exported methods. Where did I fail with generating such names for exporting-methods in the C++ dll project?
This is normal, the C++ compiler applies name decoration to functions. The C++ language supports function overloading, much like C# does. So you could write a Foo(int) and a Foo(double) function. Clearly they cannot both be exported as a function named "Foo", the client code wouldn't know which one to call. So the extra characters encode the name so that it is unique for the overload.
You can turn that off by declaring the function extern "C", the C language doesn't support overloading so doesn't require the same kind of decoration.
But it is actually better if you don't. Because it is also an excellent way to catch mistakes. Like changing the function declaration in your C++ code but forgetting to modify the pinvoke declaration in your C# code. You will now get an easy to diagnose "Entrypoint not found" exception instead of a non-descriptive and very hard to diagnose AccessViolationException. Which doesn't necessarily have to be raised in the C++ code, the stack imbalance can also crash your C# code. Looking up the decorated name is a bit painful however, improve that by asking the linker to create a map file (/MAP option).
use extern "C" to specify the linkage to avoid the name mangling:
extern "C" __declspec(dllexport) int TestCall(void);
extern "C" __declspec(dllexport) void SwapMe(int *first, int *second);

Objective c wrapper for a c file

I went through quite a number of websites, but everywhere they have given how to write a wrapper for a c++ library.
Now, I have a .c file which i want to integrate to my application. Since Objective c is an objected oriented extension of c, will i actually have to write wrapper for it? if yes, how to do it? if i dont have to, then how to use the c code in my project?
EDIT : ok.. what i have to do is add the file into my project and use the functions? how exactly to do it?? just like normal c call? what if i have to pass parameters?
Let say i have a function which returns a string, first of all how do i call that function? and if it returns a string, can i store that value in a normal NSString?? or should i declare a c string for it??
Thanks in advance
You can simply use your C code as usual:
-(void)writeString:(NSString*)data toFile:(NSString*)filename {
FILE* output = fopen([filename UTF8String], "w");
fprintf(output, "%s", [data UTF8String]);
fclose(output);
}
For other .c files, simply #include the corresponding header. Then, you can just call its functions.
For example, if this was foo.h:
int add(int a, int b);
And foo.c:
#include "foo.h"
int add(int a, int b) {
return a + b;
}
Then in your Objective-C code (Bar.m):
-(int)addA:(int)a andB:(int)b {
return add(a, b);
}
That is basically a wrapper right there. However, wrappers are not needed for C code in Objective-C. Even C++ functions do not need wrappers, as there are .mm files which are Objective-C++ sources.
Edit:
To call C functions with parameters, just call them with parameters. Literally ANY valid C program is also a valid Objective-C program. If it can compile as a .c file, it'll compile as a .m file.
To convert a C string (char*) to an NSString:
const char* myString = "Hello!";
NSString* myNSString = [NSString stringWithUTF8String:myString];

C++/CLI calling Interop wrapper methods with out parameters

I've got an Interop wrapper to some unmanaged DLL calls that return details through out paremeters. The functions appear like this:
_myWrapper->My_Method( ... out UInt32 value ... );
So assuming the method is declared like this:
void My_Method(out UInt32 value);
How do I then call this method from within my C++/CLI code? I know how to call reference methods such as this easy enough:
void Another_Method(ref UInt32 value);
UInt32 _value;
_myWrapper->Another_Method(%_value);
I'm doing a little reading and I am reading it can't be done? I don't believe it... Likely this isn't impossible to overcome or workaround, but you've got to be kidding me? Is that really true?
Thank you...
In C++, there's no special call syntax for calling a function with a reference parameter, you just write the call like it was pass-by-value. Of course, you need to supply an lvalue to be overwritten, the rvalue (temporary) result of an arithmetic expression can't be used.
BTW, your code for calling a ref function is wrong too, that might be the source of your troubles.
Example:
C# definition:
void MySharpRef(ref int i) { i = 4; }
void MySharpOut(out int i) { i = 5; }
C++/CLI definition:
void MyPlusRef(System::Int32% i) { i = 14; }
void MyPlusOut([System::Runtime::InteropServices::OutAttribute] System::Int32% i) { i = 15; }
C# call:
int j;
o.MyPlusOut(out j);
o.MyPlusRef(ref j);
C++/CLI call:
System::Int32 k;
p->MySharpOut(k);
p->MySharpRef(k);