JXA, with its built-in ObjC bridge, exposes enumeration and constants from the Foundation framework automatically via the $ object; e.g.:
$.NSUTF8StringEncoding // -> 4
However, there are also useful CFString constants in lower-level APIs that aren't automatically imported, namely the kUTType* constants in CoreServices that define frequently-used UTI values, such as kUTTypeHTML for UTI "public.html".
While you can import them with ObjC.import('CoreServices'), their string value isn't (readily) accessible, presumably because its type is CFString[Ref]:
ObjC.import('CoreServices') // import kUTType* constants; ObjC.import('Cocoa') works too
$.kUTTypeHTML // returns an [object Ref] instance - how do you get its string value?
I have yet to find a way to get at the string at the heart of what's returned:
ObjC.unwrap($.kUTTypeHTML) doesn't work, and neither does ObjC.unwrap($.kUTTypeHTML[0]) (nor .deepUnwrap()).
I wonder:
if there's a native JXA way to do this that I'm missing.
otherwise, if there's away to use ObjC.bindFunction() to define bindings for CFString*() functions that can solve the problem, such as to CFStringGetCString() or CFStringGetCStringPtr(), but it's not obvious to me how to translate the ObjC signatures.
While I don't understand all implications, the following seems to work:
$.CFStringGetCStringPtr($.kUTTypeHTML, 0) // -> 'public.html'
# Alternative, with explicit UTF-8 encoding specification
$.CFStringGetCStringPtr($.kUTTypeHTML, $.kCFStringEncodingUTF8) // ditto
The kUTType* constants are defined as CFStringRef, and CFStringGetCStringPtr returns a CFString object's internal C string in the specified encoding, if it can be extracted "with no memory allocations and no copying, in constant time" - or NULL otherwise.
With the built-in constants, it seems that a C string (rather than NULL) is always returned, which - by virtue of C data types mapping onto JXA data types - is directly usable in JavaScript:
$.CFStringGetCStringPtr($.kUTTypeHTML, 0) === 'public.html' // true
For background information (as of OSX 10.11.1), read on.
JXA doesn't natively recognize CFString objects, even though they can be "toll-free bridged" to NSString, a type that JXA does recognize.
You can verify that JXA does not know the equivalence of CFString and NSString by executing $.NSString.stringWithString($.kUTTypeHTML).js, which should return a copy of the input string, but instead fails with -[__NSDictionaryM length]: unrecognized selector sent to instance.
Not recognizing CFString is our starting point: $.kUTTypeHTML is of type CFString[Ref], but JXA doesn't return a JS string representation of it, only [object Ref].
Note: The following is in part speculative - do tell me if I'm wrong.
Not recognizing CFString has another side effect, namely when invoking CF*() functions that accept a generic type (or Cocoa methods that accept a toll-free bridged CF* type that JXA is unaware of):
In such cases, if the argument type doesn't exactly match the invoked function's parameter type, JXA apparently implicitly wraps the input object in a CFDictionary instance, whose only entry has key type, with the associated value containing the original object.[1]
Presumably, this is why the above $.NSString.stringWithString() call fails: it is being passed the CFDictionary wrapper rather than the CFString instance.
Another case in point is the CFGetTypeID() function, which expects a CFTypeRef argument: i.e., any CF* type.
Since JXA doesn't know that it's OK to pass a CFStringRef argument as-is as the CFTypeRef parameter, it mistakenly performs the above-mentioned wrapping, and effectively passes a CFDictionary instance instead:
$.CFGetTypeID($.kUTTypeHTML) // -> !! 18 (CFDictionary), NOT 7 (CFString)
This is what houthakker experienced in his solution attempt.
For a given CF* function you can bypass the default behavior by using ObjC.bindFunction() to redefine the function of interest:
// Redefine CFGetTypeID() to accept any type as-is:
ObjC.bindFunction('CFGetTypeID', ['unsigned long', [ 'void *']])
Now, $.CFGetTypeID($.kUTTypeHTML) correctly returns 7 (CFString).
Note: The redefined $.CFGetTypeID() returns a JS Number instance, whereas the original returns a string representation of the underlying number (CFTypeID value).
Generally, if you want to know the specific type of a given CF* instance informally, use CFShow(), e.g.:
$.CFShow($.kUTTypeHTML) // -> '{\n type = "{__CFString=}";\n}'
Note: CFShow() returns nothing and instead prints directly to stderr, so you can't capture the output in JS.
You may redefine CFShow with ObjC.bindFunction('CFShow', ['void', [ 'void *' ]]) so as not to show the wrapper dictionary.
For natively recognized CF* types - those that map onto JS primitives - you'll see the specific type directly (e.g., CFBoolean for false); for unknown - and therefore wrapped - instances, you'll see the wrapper structure as above - read on for more.
[1] Running the following gives you an idea of the wrapper object being generated by JXA when passing an unknown type:
// Note: CFShow() prints a description of the type of its argument
// directly to stderr.
$.CFShow($.kUTTypeHTML) // -> '{\n type = "{__CFString=}";\n}'
// Alternative that *returns* the description as a JS string:
$.CFStringGetCStringPtr($.CFCopyDescription($.kUTTypeHTML), 0) // -> (see above)
Similarly, using the known-to-JXA equivalence of NSDictionary and CFDictionary,
ObjC.deepUnwrap($.NSDictionary.dictionaryWithDictionary( $.kUTTypeHTML ))
returns {"type":"{__CFString=}"}, i.e., a JS object with property type whose value is at this point - after an ObjC-bridge call roundtrip - a mere string representation of what presumably was the original CFString instance.
houthakker's solution attempt also contains a handy snippet of code to obtain the type name of a CF* instance as a string.
If we refactor it into a function and apply the necessary redefinition of CFGetTypeID(), we get the following, HOWEVER:
A hack is needed to make it return a value predictably (see comments and source code)
Even then a random character sometimes appears as the end of the string returned, such as CFString, rather than CFString.
If anyone has an explanation for why the hack is needed and where the random characters come from, please let me know. The issues may be memory-management related, as both CFCopyTypeIDDescription() and CFStringCreateExternalRepresentation() return an object that the caller must release, and I don't know whether/how/when JXA does that.
/*
Returns the type name of the specified CF* (CoreFoundation) type instance.
CAVEAT:
* A HACK IS EMPLOYED to ensure that a value is consistently returned f
those CF* types that correspond to JS primitives, such as CFNumber,
CFBoolean, and CFString:
THE CODE IS CALLED IN A TIGHT LOOP UNTIL A STRING IS RETURNED.
THIS SEEMS TO WORK WELL IN PRACTICE, BUT CAVEAT EMPTOR.
Also, ON OCCASION A RANDOM CHARACTER APPEARS AT THE END OF THE STRING.
* Only pass in true CF* instances, as obtained from CF*() function
calls or constants such as $.kUTTypeHTML. Any other type will CRASH the
function.
Example:
getCFTypeName($.kUTTypeHTML) // -> 'CFString'
*/
function getCFTypeName(cfObj) {
// Redefine CFGetTypeID() so that it accepts unkown types as-is
// Caution:
// * ObjC.bindFunction() always takes effect *globally*.
// * Be sure to pass only true CF* instances from then on, otherwise
// the function will crash.
ObjC.bindFunction('CFGetTypeID', [ 'unsigned long', [ 'void *' ]])
// Note: Ideally, we'd redefine CFCopyDescription() analogously and pass
// the object *directly* to get a description, but this is not an option:
// ObjC.bindFunction('CFCopyDescription', ['void *', [ 'void *' ]])
// doesn't work, because, since we're limited to *C* types, we can't describe
// the *return* type in a way that CFStringGetCStringPtr() - which expects
// a CFStringRef - would then recognize ('Ref has incompatible type').
// Thus, we must first get a type's numerical ID with CFGetTypeID() and then
// get that *type*'s description with CFCopyTypeIDDescription().
// Unfortunately, passing the resulting CFString to $.CFStringGetCStringPtr()
// does NOT work: it yields NULL - no idea why.
//
// Using $.CFStringCreateExternalRepresentation(), which yields a CFData
// instance, from which a C string pointer can be extracted from with
// CFDataGetBytePtr(), works:
// - reliably with non-primitive types such as CFDictionary
// - only INTERMITTENTLY with the equivalent types of JS primitive types
// (such as CFBoolean, CFString, and CFNumber) - why??
// Frequently, and unpredictably, `undefined` is returned.
// !! THUS, THE FOLLOWING HACK IS EMPLOYED: THE CODE IS CALLED IN A TIGHT
// !! LOOP UNTIL A STRING IS RETURNED. THIS SEEMS TO WORK WELL IN PRACTICE,
// !! BUT CAVEAT EMPTOR.
// Also, sometimes, WHEN A STRING IS RETURNED, IT MAY CONTAIN A RANDOM
// EXTRA CHAR. AT THE END.
do {
var data = $.CFStringCreateExternalRepresentation(
null, // use default allocator
$.CFCopyTypeIDDescription($.CFGetTypeID(cfObj)),
0x08000100, // kCFStringEncodingUTF8
0 // loss byte: n/a here
); // returns a CFData instance
s = $.CFDataGetBytePtr(data)
} while (s === undefined)
return s
}
You can coerce a CF type to an NS type by first re-binding the CFMakeCollectable function so that it takes 'void *' and returns 'id', and then using that function to perform the coercion:
ObjC.bindFunction('CFMakeCollectable', [ 'id', [ 'void *' ] ]);
var cfString = $.CFStringCreateWithCString(0, "foo", 0); // => [object Ref]
var nsString = $.CFMakeCollectable(cfString); // => $("foo")
To make this easier to use in your code, you might define a .toNS() function on the Ref prototype:
Ref.prototype.toNS = function () { return $.CFMakeCollectable(this); }
Here is how you would use this new function with a CFString constant:
ObjC.import('CoreServices')
$.kUTTypeHTML.toNS() // => $("public.html")
$.kUTTypeHTML appears to return a CFDictionary (see below), so you should find useable methods at:
EDIT: It turns out that some typing complexities in JXA-ObjC-CF interactions mean that snippet below is NOT a reliable or generally applicable approach to learning the type of a CF Object reference. (See the discussion that follows).
https://developer.apple.com/library/mac/documentation/CoreFoundation/Reference/CFDictionaryRef/
ObjC.import('CoreServices')
var data = $.CFStringCreateExternalRepresentation(
null,
$.CFCopyTypeIDDescription(
$.CFGetTypeID($.kUTTypeHTML)
),
'UTF-8',
0
); // CFDataRef
cPtr = $.CFDataGetBytePtr(data);
// --> "CFDictionary"
Related
I am attempting a method swizzle in Obj-C but I would like to pass it a pure C function. This means I need to somehow assign a selector and/or manually build an objc_method struct. Maybe somehow leverage NSInvocation?
My understanding is that due to the fact that Obj-C is a strict superset of C and therefor fully compatible.
What I have going now:
main.m :
#include....
CFStringRef strRet(void) {
return CFSTR("retString");
}
int main(int argc, const char * argv[]) {
#autoreleasepool {
SEL _strRet = sel_registerName("strRet");
//I also tried: SEL _strRet = NSSelectorFromString(#"strRet");
Class bundle = objc_getClass("NSBundle");
method_exchangeImplementations(
class_getInstanceMethod(bundle, sel_registerName("anySelector")),
class_getInstanceMethod(bundle, sel_registerName("_strRet")
);
I have tried putting the C function inside #implementation (which I would like to avoid) and even then it did not work.
You can't swizzle a C function per se; swizzling is based on method lookup which goes through method descriptions (which are represented by the Method type by the runtime functions) and C functions do not have a method description.
However the implementation of a method is just a C function. Such a C function must take a minimum of two arguments, being the object the method is invoked on (the Objective-C implicit parameter self) and the selector (the Objective-C implicit parameter _cmd). When you swizzle a method the replacement implementation, a C function, must have exactly the same type as the original – complete with the two implicit arguments – so your strRet() would not be suitable as is, you would need to change it to:
CFStringRef strRet(NSObject *self, CMD sel, void)
{
return CFSTR("retString");
}
So you have three main choices:
The easiest way is to define a method whose body is your "pure" C function, then swizzle the recommended way (taking care to handle inheritance correctly, see this answer).
If you really want to write a C function and that C function does not need to call the original implementation of the method then:
(a) You need to convert your C function into one which can be used as a method implementation. You can:
If you are writing/have the source of the C function you simply define it to take the two implicit arguments as above. Take the address of this function and cast it to IMP, which is just a typedef for a C function pointer of the appropriate type, for use below.
If you are using a C function whose definition you cannot change then you can do one of:
Write a C wrapper function which takes the extra arguments, ignores them and calls your target C function. Take the address of this wrapper function and cast it to IMP for use below.
Wrap the call to your C function in a block and use imp_implementationWithBlock() to produce an IMP value from it. You can read this article for a description of using imp_implementationWithBlock().
(b) use method_setImplementation() to set the implementation to the IMP value you produced in (a).
If you really want to write a C function and that C function does need to call the original implementation of the method then you will need to add a method to your class whose implementation is your C function – modified/wrapped as in (2), then swizzle your added method with your original method as under (1) so that the original implementation is still available as a method. To add a method you use class_addMethod()
HTH
The key here is finding a mechanism that maps between the function pointer and your context. The simplest way to do that is by generating a new function pointer. You can use imp_implementationWithBlock(), MABlockClosure, or roll your own.
The simplest mechanism to create a new function pointer I've found is to remap the entire function to a new address space. The new resulting address can be used as a key to the required data.
#import <mach/mach_init.h>
#import <mach/vm_map.h>
void *remap_address(void* address, int page_count)
{
vm_address_t source_address = (vm_address_t) address;
vm_address_t source_page = source_address & ~PAGE_MASK;
vm_address_t destination_page = 0;
vm_prot_t cur_prot;
vm_prot_t max_prot;
kern_return_t status = vm_remap(mach_task_self(),
&destination_page,
PAGE_SIZE*(page_count ? page_count : 4),
0,
VM_FLAGS_ANYWHERE,
mach_task_self(),
source_page,
FALSE,
&cur_prot,
&max_prot,
VM_INHERIT_NONE);
if (status != KERN_SUCCESS)
{
return NULL;
}
vm_address_t destination_address = destination_page | (source_address & PAGE_MASK);
return (void*) destination_address;
}
Note that page_count should be large enough to contain all of your original function. Also, remember to handle pages that aren't required anymore and note that it takes a lot more memory per invocation than MABlockClosure.
(Tested on iOS)
From what I understand, Swift was presented as an upgrade from Objective-C for developers to use in their applications. One new concept that went with it is the concept of "optional variables," or any sort of variable that may hold nothing.
In Objective-C, this was almost implicit. You could assign a value of nil to many kinds of variables, but, in Swift, the variable has to be an optional.
For instance, this sort of statement is completely okay in Objective-C:
SKNode *someNode = [SKNode new];
// some methods appear that may change the value of "someNode."
// they are right here. These "methods" might leave "someNode"
// equal to "nil". If not, they might set "someNode" to a node
// equal to a node that exists already.
// check if it's nil.
if (someNode == nil) {
// code to run if it exists
}
else {
// code to run if it doesn't exist
}
And in Swift, this code:
var node = SKNode.new()
// this "node" is created/used like "someNode" is used above.
if node != nil {
// code that will run if node exists
}
else {
// code to run if node doesn't exist
}
will give the error:
Binary operator '!=' cannot be applied to operands of type 'SKNode' and 'nil'
However, change the Swift initialization of node to this, and you'll be gold, because you're explicitly defining node as an optional.
var node : SKNode? = SKNode.new()
May I add, this doesn't work either:
var node = SKNode?.new()
Giving the error:
'SKNode?.Type' does not have a member named 'new'
Why does the node have to be explicitly defined as an optional?
In var node : SKNode? = SKNode.new(), node has to be explicitly defined as an optional because SKNode.new() will never return nil.
The goal of types in Swift is to guarantee that once a variable is defined, its type will never change, and the variable will always have valid data. Defining a variable as an optional (SKNode?) means the variable is an Optional<SKNode> which is NOT equivalent to SKNode (hence 'SKNode?.Type' does not have a member named 'new')
The error Binary operator '!=' cannot be applied to operands of type 'SKNode' and 'nil' that you are receiving is cause because you are trying to check if a non-optional value is Optional.None (or nil), which is a completely unnecessary (and impossible) check in the language.
I want to be able to call methods on CLR classes from C++. In particular some classes may contain overloaded methods, so I need to search a class's methods based both on method name and parameter signature.
I have a function like this:
MonoMethod* find_method (
MonoDomain* domain,
MonoClass* type,
const char* name,
int nargs,
MonoClass** types)
I iterate over the members of the class, finding a matching member by name. I then need to check the parameters of the method and see whether they match the list required in the types parameter of this function.
mono_signature_get_params() is then used to iterate over the parameters for each method with a matching name.
Questions:
How can I do the following:
access the MonoClass and MonoType struct fields
attempting to access fields in these structs results in error, as incomplete structs
compare a list of method parameters with another list provided as input to the function
cannot compare by enum as cannot access the enum field (see above)
get MonoClass* constants for fundamental types int32_class, int64_class, etc.
want to be able to easily compose a signature array using primitive type class constants
Here are 2 auxilliary functions that do not compile as when accessing fields in MonoType* or MonoClass*, the compiler complains indicating the two structures are incomplete:
//
// Detetermine whether classes A and B are equivalent
//
static bool IsEquivalent (MonoType* typeA, MonoType* typeB)
{
MonoTypeEnum Ta = typeA->type;
MonoTypeEnum Tb = typeB->type;
// if basic type not a match, can punt
if (Ta != Tb)
return false;
// if simple type, nothing further to check
if (Ta < MONO_TYPE_PTR)
return true;
// check class
if (Ta == MONO_TYPE_CLASS)
return typeA->data.klass = typeB->data.klass;
else
return typeA->data.klass = typeB->data.klass;
}
//
// Determine whether parameters in signature match incoming parameters
//
static bool types_match (
MonoMethodSignature* sig,
MonoClass** types,
int nargs)
{
void* iter = NULL;
MonoType* type = NULL;
int i = 0;
while (type = mono_signature_get_params (sig, &iter))
{
if (!IsEquivalent (type, types[i++]->this_arg))
return false;
}
return true;
}
You must not include the private mono headers: your app will break when we make changes to the internals.
To access the type enum value from a MonoType* you need to call the mono_type_get_type () function (from metadata/metadata.h). For MONO_TYPE_CLASS and MONO_TYPE_VALUETYPE you can access the MonoClass* value with mono_type_get_class ().
To compare two signatures for equality you can use mono_metadata_signature_equal(): note that using MonoClass* to represent an argument's type is fundamentally incorrect, since that can't represent, for example, an argument passed by reference.
If you need to match by assignability, you can use mono_class_is_assignable_from(), but note that you will need to deal with byref arguments, decide if you want to allow enum types to autoconvert to their underlying integer type etc.
The fundamental type classes can be trivially retrieved with functions like:
mono_get_int32_class(), mono_get_boolean_class() etc.
Not sure what I'm doing wrong here. I have a struct that is used heavily through my program.
typedef struct _MyStruct {
// ... handful of non-trivial fields ...
} MyStruct;
I expect (read, intend) for lots of parts of the program to return one of these structs, but many of them should be able to return a "null" struct, which is a singleton/global. The exact use case is for the implementing function to say "I can't find what you asked me to return".
I assumed this would be a simple case of defining a variable in a header file, and initializing it in the .c file.
// MyStruct.h
// ... Snip ...
MyStruct NotFoundStruct;
-
// MyStruct.c
NotFoundStruct.x = 0;
NotFoundStruct.y = 0;
// etc etc
But the compiler complains that the initialization is not constant.
Since I don't care about what this global actually references in memory, I only care that everything uses the same global, I tried just removing the initialization and simply leaving the definition in the header.
But when I do this:
MyStruct thing = give_me_a_struct(some_input);
if (thing == NotFoundStruct) {
// ... do something special
}
Th compiler complains that the operands to the binary operator "==" (or "!=") are invalid.
How does one define such as globally re-usable (always the same memory address) struct?
This doesn't directly answer your question, but it won't fit in a comment...
If you have a function that may need to return something or return nothing, there are several options that are better than returning a "null struct" or "sentinel struct," especially since structs are not equality comparable in C.
One option is to return a pointer, so that you can actually return NULL to indicate that you are really returning nothing; this has the disadvantage of having significant memory management implications, namely who owns the pointer? and do you have to create an object on the heap that doesn't already exist on the heap to do this?
A better option is to take a pointer to a struct as an "out" parameter, use that pointer to store the actual result, then return an int status code indicating success or failure (or a bool if you have a C99 compiler). This would look something like:
int give_me_a_struct(MyStruct*);
MyStruct result;
if (give_me_a_struct(&result)) {
// yay! we got a result!
}
else {
// boo! we didn't get a result!
}
If give_me_a_struct returns zero, it indicates that it did not find the result and the result object was not populated. If it returns nonzero, it indicates that it did find the result and the result object was populated.
C doesn't allow global non-const assignments. So you must do this in a function:
void init() {
NotFoundStruct.x = 0;
NotFoundStruct.y = 0;
}
As for the comparison, C doesn't know how to apply a == operator to a struct. You can overload (redefine) the operator in C++, but not in C.
So to see if a return value is empty, your options are to
Have each function return a boolean value to indicate found or not, and return the struct's values via pointers through the argument list. (eg. bool found = give_me_a_struct(some_input, &thing);)
Return a pointer to a struct, which can be NULL if nothing exists. (eg. MyStruct* thing = give_me_a_struct(some_input);)
Add an additional field to the struct that indicates whether the object is valid.
The third option is the most generic for other cases, but requires more data to be stored. The best bet for your specific question is the first option.
// MyStruct.h
typedef struct _MyStruct {
// fields
} MyStruct;
extern MyStruct NotFoundStruct;
// MyStruct.c
#include "my_struct.h"
MyStruct NotFoundStruct = {0};
But since you can't use the == operator, you will have to find another way to distinguish it. One (not ideal) way is to have a bool flag reserved to indicate validity. That way, only that must be checked to determine if it's a valid instance.
But I think you should consider James's proposed solution instead
In the header:
// Structure definition then
extern MyStruct myStruct;
In the .c that contains global data
struct MyStruct myStruct
{
initialize field 1,
initialize field 2,
// etc...
};
Can someone please explain me the following code snippet?
value struct ValueStruct {
int x;
};
void SetValueOne(ValueStruct% ref) {
ref.x = 1;
}
void SetValueTwo(ValueStruct ref) {
ref.x = 2;
}
void SetValueThree(ValueStruct^ ref) {
ref->x = 3;
}
ValueStruct^ first = gcnew ValueStruct;
first->x = 0;
SetValueOne(*first);
ValueStruct second;
second.x = 0;
SetValueTwo(second); // am I creating a copy or what? is this copy Disposable even though value types don't have destructors?
ValueStruct^ third = gcnew ValueStruct;
third->x = 0;
SetValueThree(third); // same as the first ?
And my second question is: is there any reason to have something like that?:
ref struct RefStruct {
int x;
};
RefStruct% ref = *gcnew RefStruct;
// rather than:
// RefStruct^ ref = gcnew RefStruct;
// can I retrieve my handle from ref?
// RefStruct^ myref = ???
What is more: I see no difference between value type and ref type, since both can be pointed by handler ;(
Remember that the primary use of C++/CLI is for developing class libraries for consumption by GUIs / web services built in other .NET languages. So C++/CLI has to support both reference and value types because other .NET languages do.
Furthermore, C# can have ref parameters that are value typed as well, this isn't unique to C++/CLI and it doesn't in any way make value types equivalent to reference types.
To answer the questions in your code comments:
am I creating a copy or what?
Yes, SetValueTwo takes its parameter by value, so a copy is made.
is this copy Disposable even though value types don't have destructors?
Incorrect. Value types can have destructors. Value types cannot have finalizers. Since this particular value type has a trivial destructor, the C++/CLI compiler will not cause it to implement IDisposable. In any case, if a parameter is an IDisposable value type, the C++/CLI compiler will ensure that Dispose is called when the variable goes out of scope, just like stack semantics for local variables. This includes abnormal termination (thrown exception), and allows managed types to be used with RAII.
Both
ValueStruct% ref = *gcnew ValueStruct;
and
ValueStruct^ ref = gcnew ValueStruct;
are allowed, and put a boxed value type instance on the managed heap (which isn't a heap at all, but a FIFO queue, however Microsoft chooses to call it a heap like the native memory area for dynamic allocation).
Unlike C#, C++/CLI can keep typed handles to boxed objects.
If a tracking reference is to a value type instance on the stack or embedded in another object, then the value type content has to be boxed in the process of formed the reference.
Tracking references can also be used with reference types, and the syntax to obtain a handle is the same:
RefClass^ newinst = gcnew RefClass();
RefClass% reftoinst = *newinst;
RefClass^% reftohandle = newinst;
RefClass stacksem;
RefClass^ ssh = %stacksem;
One thing that I can never seem to remember completely is that the syntax isn't 100% consistent compared to native C++.
Declare a reference:
int& ri = i; // native
DateTime% dtr = dt; // managed tracking reference
Declare a pointer:
int* pi; // native
Stream^ sh; // tracking handle
Form a pointer:
int* pi = &ri; // address-of native object
DateTime^ dth = %dtr; // address-of managed object
Note that the unary address-of operator is the same as the reference notation in both standard C++ and C++/CLI. This seems to contradict a tracking reference cannot be used as a unary take-address operator (MSDN) which I'll get back to in a second.
First though, the inconsistency:
Form a reference from a pointer:
int& iref = *pi;
DateTime% dtref = *dth;
Note that the unary dereference operator is always *. It is the same as the pointer notation only in the native world, which is completely opposite of address-of which, as mentioned above, are always the same symbol as the reference notation.
Compilable example:
DateTime^ dth = gcnew DateTime();
DateTime% dtr = *dth;
DateTime dt = DateTime::Now;
DateTime^ dtbox = %dt;
FileInfo fi("temp.txt");
// FileInfo^ fih = &fi; causes error C3072
FileInfo^ fih = %fi;
Now, about unary address-of:
First, the MSDN article is wrong when it says:
The following sample shows that a tracking reference cannot be used as a unary take-address operator.
The correct statement is:
% is the address-of operator for creation of a tracking handle. However its use is limited as follows:
A tracking handle must point to an object on the managed heap. Reference types always exist on the managed heap so there is no problem. However, value types and native types may be on the stack (for local variables) or embedded within another object (member variables of value type). Attempts to form a tracking handle will form a handle to a boxed copy of the variable: the handle is not linked to the original variable. As a consequence of the boxing process, which requires metadata which does not exist for native types, it is never possible to have a tracking handle to an instance of a native type.
Example code:
int i = 5;
// int^ ih = %i; causes error C3071
System::Int32 si = 5;
// System::Int32^ sih = %si; causes error C3071
// error C3071: operator '%' can only be applied to an instance
// of a ref class or a value-type
If System::Int32 isn't a value type then I don't know what is. Let's try System::DateTime which is a non-primitive value type:
DateTime dt = DateTime::Now;
DateTime^ dtbox = %dt;
This works!
As a further unfortunate restriction, primitive types which have dual identity (e.g. native int and managed value type System::Int32) are not handled correctly, the % (form tracking reference) operator cannot perform boxing even when the .NET name for the type is given.