I posted an example that wraps up the discussion of using native structs with manage code using C++/CLI. This example depends on the Windows Mobile 6 SDK. The SDK will need to be installed on your development system and wired in to your VS 2005 environment. I have not tested this code with VS 2008. It may work, it may not.
Here's the link on my wiki: Example C++/CLI mixed mode applied to RAPI
The Code Wizard's Musings - Old Blog
Remnants of articles on C++ and life.
Thursday, July 3, 2008
Example C++/CLI mixed mode applied to RAPI
Tuesday, July 1, 2008
Native pointers and managed code
My last two posts were aimed at the integration of native types into managed classes. VC2005 does not support the use of mixed native/managed member variables in a managed class. You can have a pointer to a native type as a member variable, but you cannot declare a native type.
Thanks to some excellent work by Brandon Bray, we've learned it is possible to have a nested class that creates an instance of the native object and exposes a pointer to that object. Brandon published a template that I have reproduced here:
template<typename T>
ref class Embedded {
T* t;
!Embedded() {
if (t != nullptr) {
delete t;
t = nullptr;
}
}
~Embedded() {
this->!Embedded();
}
public:
Embedded() : t(new T) {}
static T* operator&(Embedded% e) { return e.t; }
static T* operator->(Embedded% e) { return e.t; }
};
Using Brandon's template, and some of the experimental code I presented in the last two posts, you can do some very interesting things with native structs contained in a managed class.Let's look at some code fragments that utilize Brandon's template:
public ref class FileInformation
{
private:
// This is an embedded class that wraps our native type
Embedded<CE_FIND_DATA> fi;
...
// Operator returns a pointer to a native CE_FIND_DATA structure
static operator LPCE_FIND_DATA (FileInformation^ value)
{
// Reference the address of fi, the native object
// and cast the return to an LPCE_FIND_DATA.
return (LPCE_FIND_DATA) &(value->fi);
}
The template creates the native type in the ctor initialization and exposes a pointer to it. The operator overload method allows the class to expose a native pointer to the native class. This allows the managed class to be used in a native API call:... FileInformation^ finfo = gcnew FileInformation(); // This statement is why I was so interested in being able to // use memcpy in my last post. By exposing a pointer to the // struct definition, we can blt data in and out. HANDLE hSearch = ::CeFindFirstFile(pFileName, (LPCE_FIND_DATA) fi); // Access the native type member variables like this // finfo->fi->cFileName; ...While this is not direct compiler support of mixed native/managed member variables, it is very useful.
Labels:
C++,
CE_FIND_DATA,
CeFindFirstFile,
CLI,
templates
Monday, June 30, 2008
Experiments with native strings and managed byte arrays
Or, How to convert between a native unicode string and a managed byte array
Update: I've expanded this work on my web site. I've written four new articles at My C++/CLI workI've been playing around with manipulating managed byte arrays and native strings. It's possible to do a number of useful transformations between the two types in C++/CLI mixed mode programming.
Here is one example, compiled using Unicode character sets:
// Create a pointer to a native string
LPTSTR strT = _T("This is a test string.");
// Create an empty byte array
array<unsigned char>^ pBuf = gcnew array(100);
// Create a pinned pointer to the first byte in the array
pin_ptr<unsigned char> ptrBuf = &pBuf[0];
// Assign the pointer to a native byte pointer
LPBYTE lpBuf = ptrBuf;
// Copy the native string to the byte array
memcpy(lpBuf, strT, sizeof(TCHAR) * _tcslen(strT));
// Get a reference to the string
String^ tT = Encoding::Unicode->GetString(pBuf, 0, sizeof(TCHAR) * _tcslen(strT));
// tT now points to a String containing "This is a test string."
The above code isn't too exciting. (Nach!)However, we now have the possibility of loading a native struct into a managed byte array using a fast
memcpy call rather than a slow Marshal::Copy call. The important point of these experiments? We might be able to place a native struct in a ref class and then load it by performing a memcpy operation. Now this might make things a lot faster without a lot of marshaling code.For operations like
FindFirstFile and FindNextFile API calls using P/Invoke, maybe we can speed them up a little? First, here is an example of an inefficient means of locating files in my screwturn wiki. I'll follow up with a much faster version in a day or two.Sunday, June 29, 2008
Using managed vars in C++/CLI mixed mode programming
I am in the process of writing a managed wrapper for some API functionality. Here are some useful managed to unmanaged conversions I use in mixed mode:
// Test getting a pointer to a string
String^ RemoteFileName = gcnew String("C:\\temp\\test.txt");
pin_ptr prfn = PtrToStringChars(RemoteFileName);
LPCWSTR pRemoteFileName = prfn;
// You should not change the String! Strings are immutable in CLR.
// The buffer pointed to by pRemoteFileName is constant
_tprintf (_T("%s\n"), prfn);
_tprintf (_T("%s\n"), pRemoteFileName);
// Using a managed boolean in unmanaged code
Boolean mbTest = true;
DWORD dwCreateDisposition = (mbTest ? CREATE_ALWAYS : CREATE_NEW);
// DateTime converstion to FILETIME
// Convert from managed DateTime to FILETIME struct
DateTime^ a = gcnew DateTime(2008, 6, 28, 17, 35, 0);
__int64 b = a->ToFileTimeUtc();
// Native conversion
FILETIME ft;
ft.dwLowDateTime = (UInt32) (b & 0xFFFFFFFF);
ft.dwHighDateTime = (UInt32) (b >> 32);
// Convert from native FILETIME struct to managed DateTime
__int64 c = (((__int64) ft.dwHighDateTime) << 32) +
(__int64) ft.dwLowDateTime;
// Get the DateTime back. (It had better be the same.)
DateTime dte = DateTime::FromFileTimeUtc(c);
I've written up a larger example of using this type of C++/CLI code in my screwturn wiki.
Labels:
Boolean,
C++,
CLI,
DateTime,
FromFileTimeUtc,
pin_ptr,
PtrToStringChars,
String,
ToFileTimeUtc