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

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

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.

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 work

I'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.