My C++ DLL has function:
void allocate(double *&arr_not_allocated, UINT &arrayCount);
Normally, I pass into C++ from C# with:
allocate(out IntPtr arr_not_allocated, ref uint arrayCount)
I am just wondering what would be the equivalent call into C++ using C++/CLI instead of the above C#?
I should also note that I have no desire to hold the allocated array in managed memory(only in unmanaged), so I do not care to Marshal any structures on the managed side.
I just want to get the native pointer back from C++ and possibly pass the unmanaged array's address back to C++ in the future. So that is why I was using IntPtr in the past with P/Invoke.
Thanks!
In C++, pass by reference is completely transparent at the caller site. It doesn't distinguish between by-reference parameters used for input, output, or both. But it also does not permit variable declarations inside a function call, so you must declare those in advance. Final code is quite simple:
double* arr_not_allocated;
UINT arrayCount = whatever;
allocate(arr_not_allocated, arrayCount);
/* now both arrayCount and arr_not_allocated have been updated by the function */
If you don't have an import library, you may have to use LoadLibrary() and pass the resulting handle to GetProcAddress. The result of GetProcAddress gets cast to the correct function pointer type, i.e. typedef void (*allocate_fnptr)(double*&, UINT&);
I didn't include a calling convention, because your question didn't specify one. But you may need to throw a __cdecl or __stdcall into the function pointer type.
Related
I'm working on a brigde class to work with a unmanaged c++ library. I've a problem with the following (reduced) example code:
ref class ManagedClass
{
private:
UnManagedClass* m_UnManaged;
String^ m_someString;
public:
UserAgent_Managed(String^ someString)
{
m_someString = someString;
// Compiler error
// Severity Code Description Project File Line Suppression State Error C2665 'msclr::interop::marshal_as': none of the 3 overloads could convert all the argument
// types
std::string unManagedString = msclr::interop::marshal_as<std::string>(m_someString);
// Following works
// std::string unManagedString = msclr::interop::marshal_as<std::string>(someString);
m_UnManaged = new UnManagedClass(unManagedString);
}
};
When I call std::string unManagedString = msclr::interop::marshal_as<std::string>(m_someString); with the object attribute m_someString, the compiler tells me that there is no matching marshal_as method signature. If I perform the same with the someStringparameter the compiler doesn't throw an error. What am I missing? Both m_someStringand someString have the type String^.
Thx
The marshal_as() function is not very friendly, it is missing an overload to allow this code to compile. You can hone down the problem by looking at the IntelliSense popup that shows which overloads are available. The one you are trying to use is the 4th:
std::string marshal_as<std::string, System::String^>(System::String^ const & _from_obj)
The devil is in &, an unmanaged reference. Yes, an unmanaged reference to a managed object reference, mind blown :) But perfectly legal in C++/CLI, at runtime this argument turns into a raw pointer to the object reference.
It would have compiled if the template offered a System::String^ % _from_obj overload. It doesn't. The distinction between % and & matters a lot in C++/CLI, % declares a managed reference. Called a "tracking reference" in the docs. One that the garbage collector knows about and can update when it compacts the GC heap. Otherwise semantically completely identical to an unmanaged reference.
That the GC cannot update a & reference is the hang-up here. The compiler outright forbids generating unmanaged pointers to members of a managed type, other than through pin_ptr<>. It is far too dangerous, the garbage collector can kick in any time, even while the marshal_as() function is executing. Triggered by, say, another thread that allocates objects. And move the ManagedClass object, invalidating any raw pointers to the object. Having the function continue to use the outdated pointer at runtime will make the function produce garbage and possibly corrupt the GC heap.
The someString object reference is very different, it is stored on the stack or a processor register and cannot change when a collection occurs. So no complaints from the compiler.
You already have a good workaround here, the constructor argument is good as-is. But usually you have to provide one explicitly and store the member value into a local variable. In other words, write something like this:
auto temp = this->m_someString; // Intentional temporary
auto str = marshal_as<std::string>(temp);
Following is a self referential struct from C++
typedef struct _FCV
{
unsigned long ulID;
unsigned long ulVersion;
unsigned long ulStatus;
unsigned long ulSize;
struct _FCV* pNext;
} FCV;
I need to use PInvoke to translate to C# struct,
What is the "pNext" i should declare?
Thank you.
You have perhaps reached the point where p/invoke is not the best tool for the job. The complexity here may make a C++/CLI layer a more attractive option.
With p/invoke you'd need to declare the pNext field as IntPtr. Then you'd need to populate one instance of the struct for each item in the linked list. Finally you'd need to walk through the list assigning to pNext. That will require you to pin each struct with GCHandle.Alloc and then get the pinned address with AddrOfPinnedObject. Once the call has been made you then need to destroy all the GCHandle objects to un-pin the structs.
So it's possible to do, but the code may be rather unwieldy, and may not be particularly efficient. You should seriously consider C++/CLI instead.
I have this problem. This the external library that i must use in .h file:
typedef struct _IPCSSContext IPCSSContext;
IPCSSContext * ipcssnew(const IPCSSCfg *_config, const IPCSSCallbacks *_callbacks, void *_user);
How can I use? Thanx
First you define a variable of type IPCSSCallbacks whatever that might be, but it's probably a struct of function pointers.
Then you fill in the fields of the variable with pointers to your callback functions.
Then you call icssnew() passing the IPCSSCallbacks, the config and a pointer to anything you like. This pointer will be passed untouched to your callback functions when they are called and you can do what you like with it in the callbacks (including nothing).
This is a pretty standard pattern in C for performing callbacks.
I have an unmanaged code with a fixed struct in memory, i need to read and write the struct from the managed side; the application is a real-time application and i cannot afford the struct's marshalling every time i need it, so i think is better to work in an unsafe context(for performance) and directy handle the pointer.
If i have this signature:
public static extern IntPtr COLM104_GetGlobalConf();
and my pointer is a RuntimeDescriptor*, can i store directly store the RuntimeDescriptor* as an object's field or i must keep the pointer in an IntPtr and every time i need it i should do:
(RuntimeDescriptor*)pointerField.ToPointer()
and last thing, can i directly change the p/invoke signature with:
public static extern RuntimeDescriptor* COLM104_GetGlobalConf();
Any help will be apreciated.
You can declare an unsafe member of type RuntimeDescriptor*. And you can declare the return value of your p/invoke to be of type RuntimeDescriptor*.
However, it doesn't really gain you any performance over a cast to RuntimeDescriptor*. Certainly with optimisations enabled, the compiler doesn't need to emit any actual code to perform the cast. However, if you are going down the route of using unsafe code then it's cleaner to be all-in. Declaring the member and return type to be RuntimeDescriptor* makes your program easier to read.
FWIW, there's no need for the call ToPointer() in the code in your question. You can write that cast like this:
(RuntimeDescriptor*)pointerField
I'm calling a C method which returns a pointer or 'handle' to a resource. I just need to hold the void* in order to pass it in again later.
In .NET, I might use IntPtr. The only different between IntPtr and just an int--other than making the pointer a more strongly typed variable--is that IntPtr is automatically the size of the platform (32 or 64 bits). I'm looking for the same thing in Objective-C.
Is there some equivalent way to wrap a pointer in Objective-C?
Have you looked at NSValue's + (NSValue *)valueWithPointer:(const void *)aPointer?
Since Objective-C is a superset of C, you can simply use void *.