P/Invoke for pointer to array of char - pinvoke

I have a DLL that I need to P/Invoke the following method:
DWORD Foo(
int a,
int *b,
char *c
);
Per the documentation, parameter 'c' is an out parameter that must be a char array of size 16. A null terminated string is placed into it.
What is the P/Invoke definition for parameter 'c' (I've got the others fine)? How is the content of 'c' read after the call?

I prefer to use StringBuilder for these things actually. It's far easier to deal with than char arrays or immutable strings. Just make sure you initialize it with enough capacity (16 in this case) for the DLL to fill. Typically it marshalls over just fine, but you may have to set the character set in your DLLImport declaration.
Here is a little more info on this:
Marshaling between Managed and Unmanaged Code from MSDN magazine (Stringbuilder section)

Related

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.

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.

How to access a character in NSMutableString Objective-C

I have an instance of NSMutableString called MyMutableStr and I want access its character at index 7.
For example:
unsigned char cMy = [(NSString*) MyMutableStr characterAtIndex:7];
I think this is an ugly way; it's too much code.
My question is: Are there more simple ways in Objective-C to access the character in NSMutableString?
Like, in C language we can access a character of a string using [ ] operator:
unsigned char cMy = MyMutableStr[7];
The way of doing it is to use characterAtIndex:, but you don't need to cast it to a NSString pointer, since NSMutableString is a subclass of NSString. So it isn't that long, but if you still don't find it comfortable, I suggest to use UTF8String to obtain a C string over which you can iterate using the brackets operator:
const char* cString= [MyMutableStr UTF8String];
char first= cString[0];
But remember this (taken from NSString class reference):
The returned C string is automatically freed just as a returned object would be released; you should copy the C string if it needs to store it outside of the autorelease context in which the C string is created.
As others said characterAtIndex: but a few things you might want to consider carefully.
First you're dealing with an mutable string. You want to be careful to avoid it changing out from under you. One way is to an immutable copy and use that for the op.
Second, you're dealing with Unicode so you may want to consider normalizing your string to get a precomposed form as some visual representations may be more than one actual unichar. That's often a stumbling block for folks.

Objective-C pointer values

I'm compiling an application using X-Code 3.2.6 (64-bit). The application is compiling against the 10.5 SDK and in 32 Bit Intel Architecture.
I've declared a character array as:
char iptmp[ARRAY_SIZE];
so I'm calling a function thus:
myfunc(&iptmp);
Where myfunc is declared:
void myfunc(char** value)
{
...
};
With the intention of loading the character array with the contents of another string with strncpy. When you see what's below you might appreciate why I don't simply do something like: strcpy(iptmp, myfunc()); but here is the problem:
Value of iptmp prior to function call: 0xb0206f5a
Value of *value in function: 0xffffb020
I've tried various things to resolve this problem, but the only thing that seems to stick is to receive a UINT32 value and cast:
myfunc((UINT32) &iptmp);
void myfunc(UINT32 value)
{
char* target = (char*) value;
...
}
This is causing havoc in my code. What is going on with the pointer value?
What happens here is that iptmp is a location in memory. If you write iptmp you will get the address of the aray. However, you will also get the address of it if you write &iptmp. However, you assume that you will get a pointer to a pointer to the array.
The best way to handle this is simply doing:
void myfunc(char * value)
{
...
};
The pointer value will point to the array, which you can modify anyway you like.
When you derefence *value, you're saying "take the pointer stored in value, and load the bytes at that location as if they were a char *". But the bytes at the location pointed to by value aren't a char * - they're the first bytes of iptmp[] itself (in your case, the first 4 bytes).
The root cause is that you're passing &iptmp, which has type char (*)[ARRAY_SIZE], to a function that expects a char ** parameter. These types are not interchangeable, as you've found. The correct declaration for the function would be:
void myfunc(char (*value)[ARRAY_SIZE])
{
/* ... */
}
You can then pass &iptmp, and you will find that *value has the value that you expect.
Why not just
void myfunc(char *value)
{
strncpy(value, ...);
}
and
myfunc(iptmp);
Remember, arrays and pointers in C are not the same things, although you may have heard the opposite many times. An array is an object whose size is equal to its length multiplied by the size of each of its elements, while a pointer is just like a single int but with special semantics.
Hence, the two expressions iptmp and &iptmp yield the same result, namely the starting address of the array. iptmp yields a pointer value for convenience, but that doesn't mean that the object iptmp is a pointer itself.
By attempting to get the address of the address of the array, you really intend to perform &(&iptmp), which is a meaningless, erroneous operation.

Unfamiliar C syntax in Objective-C context

I am coming to Objective-C from C# without any intermediate knowledge of C. (Yes, yes, I will need to learn C at some point and I fully intend to.) In Apple's Certificate, Key, and Trust Services Programming Guide, there is the following code:
static const UInt8 publicKeyIdentifier[] = "com.apple.sample.publickey\0";
static const UInt8 privateKeyIdentifier[] = "com.apple.sample.privatekey\0";
I have an NSString that I would like to use as an identifier here and for the life of me I can't figure out how to get that into this data structure. Searching through Google has been fruitless also. I looked at the NSString Class Reference and looked at the UTF8String and getCharacters methods but I couldn't get the product into the structure.
What's the simple, easy trick I'm missing?
Those are C strings: Arrays (not NSArrays, but C arrays) of characters. The last character is a NUL, with the numeric value 0.
“UInt8” is the CoreServices name for an unsigned octet, which (on Mac OS X) is the same as an unsigned char.
static means that the array is specific to this file (if it's in file scope) or persists across function calls (if it's inside a method or function body).
const means just what you'd guess: You cannot change the characters in these arrays.
\0 is a NUL, but including it explicitly in a "" literal as shown in those examples is redundant. A "" literal (without the #) is NUL-terminated anyway.
C doesn't specify an encoding. On Mac OS X, it's generally something ASCII-compatible, usually UTF-8.
To convert an NSString to a C-string, use UTF8String or cStringUsingEncoding:. To have the NSString extract the C string into a buffer, use getCString:maxLength:encoding:.
I think some people are missing the point here. Everyone has explained the two constant arrays that are being set up for the tags, but if you want to use an NSString, you can simply add it to the attribute dictionary as-is. You don't have to convert it to anything. For example:
NSString *publicTag = #"com.apple.sample.publickey";
NSString *privateTag = #"com.apple.sample.privatekey";
The rest of the example stays exactly the same. In this case, there is no need for the C string literals at all.
Obtaining a char* (C string) from an NSString isn't the tricky part. (BTW, I'd also suggest UTF8String, it's much simpler.) The Apple-supplied code works because it's assigning a C string literal to the static const array variables. Assigning the result of a function or method call to a const will probably not work.
I recently answered an SO question about defining a constant in Objective-C, which should help your situation. You may have to compromise by getting rid of the const modifier. If it's declared static, you at least know that nobody outside the compilation unit where it's declared can reference it, so just make sure you don't let a reference to it "escape" such that other code could modify it via a pointer, etc.
However, as #Jason points out, you may not even need to convert it to a char* at all. The sample code creates an NSData object for each of these strings. You could just do something like this within the code (replacing steps 1 and 3):
NSData* publicTag = [#"com.apple.sample.publickey" dataUsingEncoding:NSUnicodeStringEncoding];
NSData* privateTag = [#"com.apple.sample.privatekey" dataUsingEncoding:NSUnicodeStringEncoding];
That sure seems easier to me than dealing with the C arrays if you already have an NSString.
try this
NSString *newString = #"This is a test string.";
char *theString;
theString = [newString cStringWithEncoding:[NSString defaultCStringEncoding]];