P/Invoke Unmanaged Pointer, as IntPtr or as void* - pinvoke

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

Related

Converting PInvoke call to C++/CLI

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.

Isn't pointer type checking disabled in DLL/C-Connect, and is that OK?

After this somehow related question Why can't I pass an UninterpretedBytes to a void* thru DLL/C-Connect? where we saw that I could not pass a Smalltalk array of bits to a void * parameter, I further analyzed the method responsible for checking the compatibility of formal pointer description with effective object passed as argument, and I think that I discovered another questionable piece:
CPointerType>>coerceForArgument: anObject
...snip...
(anObject isKindOf: self defaultDatumClass)
ifTrue: [
(referentType = anObject type referentType
or: [(referentType isVoid
and: [anObject type referentType isConstant not])
or: [anObject type isArray not
or: [anObject type baseArrayType = referentType]]])
ifTrue: [^anObject asPointer]].
...snip...
It means the following:
It first checks if the argument is CDatum (a proxy to some C-formatted rawdata and associated CType).
If so, it checks whether the type is the same as the formal definition in external method prototype (self).
If not, it could be that the argument is void *, in which case any kind of pointer is accepted (it has been checked that it is a pointer in the code that I snipped), except if it is pointer on a const thing.
There is a first discrepancy: it should check if the formal definition is const void * and accept any pointer on const in this case... But that does not matter much, we rarely have actual argument declared const.
If not, it checks if either not an array (for example, int foo[2]), or an array whose type matches (same base type and dimension).
So, if the formal definition is for example struct {int a; char *b} *foo, and that I pass a double * bar, the type does not match, there is no const qualifier mismatch, and the parameter is not an array, conclusion: we can safely pass it without any further checking!
That's a kind of pointer aliasing. We do not have an optimizing compiler making any speculation about the absence of such aliasing in Smalltalk, so that won't be the source of undefined behaviour. It could be that we deliberately want to force this sort of dirty reinterpret_cast for obscure reasons (since we can explicitly cast a CDatum, I would prefer the explicit way).
BUT, it might be that we completely messed up and passed the wrong object, with wrong type, wrong dimension, and that the address foo->b in my example above will contain either some re-interpreted garbage if pointer is 32bits aligned, or be completely undefined on 64 bits machine (because beyond the sizeof double).
A C compiler would warn me for sure about the aliasing, and prevent production of artifact with -Wall -Werror.
What troubles me here is that I do not even get a warning...
Does it sound correct?
Short answer: it's not OK to correct this behavior, because some low level user interface stuff depends on it (event loop). We can't even introduce a Warning or anything.
Longer story: I tried to rewrite the whole method with double dispatching (ask anObject if compatible with formal CPointerType rather than testing every possible Object class with repeated isKindOf: ).
But when ommitting the disgracious pointer aliasing tolerance, it invariably screw my Macosx 8.3 image with tons of blank windows opening, and blocked uninterruptable UI...
After instrumenting, it appears that the event loop relies on it, and pass aString asNSString (which is transformed into utf16, but stored into a ByteArray and thus declared unsigned char *), to an Objective C method expecting an unsigned short *.
It's a case where the pointer aliasing is benign, as long as we pass the good bytes.
If I try and fix asNSString with a proper cast to unsigned short *, then the UI blocks (I don't know why, but it would require debugging at VM level).
Conclusion: it's true that some distinction such as (unsigned char *) vs (char *) can be germane and should better not be completely prohibited (whether char is signed or not is platform dependent, and not all libraries have cleanly defined APIs). Same goes with platform dependent wide character, we have conversion methods producing the good bytes, but not the good types. We could eventually make an exception for char * like we did for void * (before void * was introduced, char * was the way to do it anyway)... Right now, I have no good solution for this because of the event loop.

Marshall object attribute generates compiler error

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);

PInvoke of self referential struct from C++

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.

What is the biggest advantage of using pointers in ObjectiveC

I realize 99% of you think "what the h***…" But please help me to get my head around the this concept of using pointers. I'm sure my specific question would help lots of newbies.
I understand what pointers ARE and that they are a reference to an adress in memory and that by using the (*) operator you can get the value in that address.
Let's say:
int counter = 10;
int *somePointer = &counter;
Now I have the address in memory of counter, and I can indirectly point to its value by doing this:
int x = *somePointer;
Which makes x = 10, right?
But this is the most basic example, and for this case I could use int x = counter; and get that value, so please explain why pointers really are such an important thing in Objective-C and some other languages... in what case would only a pointer make sense?
Appreciate it.
Objective-C has pointers because it is an evolution of C, which used pointers extensively. The advantage of a pointer in an object-oriented language like Objective-C is that after you create an object, you can pass around a pointer to the object instead of passing around the object itself. In other words, if you have some object that takes up a large amount of storage space, passing around a pointer is a lot more memory-efficient than passing around a copy of the object itself. This may not be noticeable in simple cases when you’re only dealing with primitive types like ints, but when you start dealing with more complex objects the memory and time savings are enormous.
More importantly, pointers make it much easier for different parts of your code to talk to each other. If variables could only be passed to functions “by value” instead of “by reference” (which is what happens when you use pointers), then functions could never alter their inputs. They could only change the state of your program by either returning a value or by changing a global variable—the overuse of which generally leads to sloppy, unorganized code.
Here’s a concrete example. Suppose you have an Objective-C method that will parse a JSON string and return an NSDictionary:
+ (NSDictionary *)parseJsonString:(NSString *)json
error:(NSError **)error;
The method will do the parsing and return an NSDictionary if everything goes okay. But what if there’s some problem with the input string? We want a way to indicate to the user (or at least to the programmer) what happened, so we have a pointer to a pointer to an NSError, which will contain that information. If our method fails (probably returning nil), we can dereference the error parameter to see what went wrong. What we’ve effectively done is to give our method two different kinds of return values: usually, it will return an NSDictionary, but it could also return an NSError.
If you want to read more about this, you may have better luck searching for “pointers in C” rather than “pointers in Objective-C”; pointers are of course used extensively in Objective-C, but all of the underlying machinery is identical to that of C itself.
What is the biggest advantage of using pointers in ObjectiveC
I'd say the biggest advantage is that you can use Objective-C at all - all Objective-C objects are pointers are accessed using pointers (the compiler and the runtime won't let you create objects statically), so you wouldn't get any further without them...
Item:
What if I told you to write me a program that would maintain a set of counters, but the number of counters would be entered by the user when he started the program. We code this with an array of integers allocated on the heap.
int *counters = malloc(numOfCounters * sizeof(int));
Malloc works with memory directly, so it by nature returns a pointer. All Objective-C objects are heap-allocated with malloc, so these are always pointers.
Item:
What if I told you to write me a function that read a file, and then ran another function when it was done. However, this other function was unknown and would be added by other people, people I didn't even know.
For this we have the "callback". You'd write a function that looked like this:
int ReadAndCallBack(FILE *fileToRead, int numBytes, int whence, void(*callback)(char *));
That last argument is a pointer to a function. When someone calls the function you've written, they do something like this:
void MyDataFunction(char *dataToProcess);
ReadAndCallBack(myFile, 1024, 0, MyDataFunction);
Item:
Passing a pointer as a function argument is the most common way of returning multiple values from a function. In the Carbon libraries on OSX, almost all of the library functions return an error status, which poses a problem if a library function has to return something useful to the programmer. So you pass the address where you'd like the function to hand information back to you...
int size = 0;
int error = GetFileSize(afilePath,&size);
If the function call returns an error, it is in error, if there was no error, error will probably be zero and size will contain what we need.
The biggest advantage of pointers in Objective-C, or in any language with dynamic allocation, is that your program can handle more items than the names that you invent in your source code.