Managed C++ - Arrays, Handles

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

I am trying to develop a managed C++ assembly that returns information in the registry. I am having two problems

1) In the constructor I would like to initialize the registry key using RegOpenKeyEx. But if I have the HKEY value as a private member the compiler complains that HKEY __gc cannot be converted to PHKEY. How do I tell it not to treat it as a managed object? __nogc can only be used for classes

2) I want to build an array from querying the registry keys to I have a property

__property String * get_TimeZoneList() [

ArrayList *names = new ArrayList()
return (String * [])names->ToArray(__typeof(String))
}

Compiling this gives me an error

d:\TimeZone\TimeZone.h(49): error C2440: 'type cast' : cannot convert from 'System::Array __gc *' to 'System::String __gc * __gc[]

Any suggestions on either of these problems

Thank you

Kevi
 
Kevin said:
I am trying to develop a managed C++ assembly that returns
information in the registry. I am having two problems:

1) In the constructor I would like to initialize the registry key
using RegOpenKeyEx. But if I have the HKEY value as a private member
the compiler complains that HKEY __gc cannot be converted to PHKEY.

You are doing soemthing like this:

__gc class Registry
{
private:
HKEY key;
public:
Registry(char* s)
{
RegOpenKeyEx(HKEY_CURRENT_USER, s, 0, ALL_KEY_ACCESS, &key);
}
}

The problem is that the object is allocated on the managed heap, this means
that *any* pointer to any member in the object is a pointer to memory in the
managed heap. At any point in time the GC could compact the heap and move
your object, that means that those pointers must be updated. This is why the
compiler says that you have a HKEY __gc pointer, because only a __gc pointer
can be tracked by the GC. You cannot convert a __gc pointer to an unmanaged
pointer, because unmanaged code does not know about __gc pointers, and
because once the pointer goes into unmanaged code the GC cannot track it.

The solution is to make sure that the object will not move while the pointer
is passed to the unmanaged code. To do this you have to pin the pointer:

HKEY __pin* pKey = &key;
RegOpenKeyEx(HKEY_CURRENT_USER, s, 0, ALL_KEY_ACCESS, &pKey);

The __pin tells the runtime that the item pointed to, and hence the object
that contains it, cannot move in memory while the pointer is pinned. The
pinning lasts for the lifetime of the method. A pinned pointer can be
converted to an unmanaged pointer.
How do I tell it not to treat it as a managed object? __nogc can only
be used for classes.

You don't.

BTW you do make your class implement IDisposable, don't you? If you hold
unmanaged handles in a managed class you have to make sure that those
handles are released as soon as possible, so you should have a Dispose() and
a Finalizer (C++ destructor).
2) I want to build an array from querying the registry keys to I have
a property:

__property String * get_TimeZoneList() []
{
ArrayList *names = new ArrayList();
return (String * [])names->ToArray(__typeof(String));
};

Compiling this gives me an error:

d:\TimeZone\TimeZone.h(49): error C2440: 'type cast' : cannot convert
from 'System::Array __gc *' to 'System::String __gc * __gc[]'

*Never* use C-style casts with managed C++, use the C++ casts instead:
dynamic_cast, static_cast and reinterpret_cast.

In your example because you know the type of the array at compile time use
static_cast:

__property String * get_TimeZoneList() []
{
ArrayList *names = new ArrayList();
return static_cast<String * []>(names->ToArray(__typeof(String)));
}

This tells the compiler to ignore type checking and just treat the return
from ToArray() as a String*[].

Richard
 
Back
Top