Home > Articles > Programming > Windows Programming

  • Print
  • + Share This
This chapter is from the book

This chapter is from the book

Pocket PC and P/Invoke

The last topic we are going to cover regarding the .NET Compact Framework is its ability to call into unmanaged code using Platform Invoke (P/Invoke). As you have seen throughout this book, most of the APIs that are supported on a Pocket PC platform are exported by using dynamic link libraries (DLLs) that your application imports. By using the P/Invoke service, you can also access the same API functions from within a .NET application. This enables you to integrate much of the functionality that is native to the Pocket PC, and not natively supported by the Compact Framework. For example, the Pocket PC Phone Edition supports the capability to send and receive SMS messages (see Chapter 8). Although the Compact Framework does not come with any classes to support this, you can use P/Invoke to enable your managed code to call into the unmanaged SMS API found in the cellcore.dll library.

To declare within your application a method that will use P/Invoke, you need to use the DllImport attribute, which supports the fields described in Table 12.16.

Table 12.16. DllImport Attributes




The function name that you want to call into


Specifies how the string arguments should be marshaled


Specifies the calling convention to use when passing arguments


Set this value to TRUE to enable calling the Marshal.GetLastWin32Error method to check if an error occurred when invoking this method

For example, the following code shows how you can use the MessageBox() function from a managed application by using P/Invoke:

using System;
using System.Data;
using System.Runtime.InteropServices;

namespace invokeTest {
   class Class1 {
        // Hook up Windows API methods
        [DllImport("coredll.dll", EntryPoint="MessageBox",
           CharSet=CharSet.Unicode, SetLastError=true)]
        static extern Int32 MessageBox(Int32 hWnd, string
           string stCaption, Int32 mbType);

        static void Main(string[] args) {
           // Call into the MessageBox function
           MessageBox(0, "MessageText", "MessageCaption", 0);

Once a function has been declared with the DllImport attribute, you can then call it in the same manner as any other managed function.

Note a few minor differences regarding P/Invoke on the .NET Compact Framework when comparing it to its desktop counterpart:

  • There is no Unicode-to-ANSI string conversion. All string pointers are passed to an unmanaged function as a Unicode string.

  • There is no marshaling of objects contained within structures.

  • If a function returns a pointer to a structure, it is not marshaled to a managed structure. You need to create a wrapper function that handles simple data types.

  • Platform Invoke services does not support COM interoperability with the Compact Framework. If you wish to call into COM objects, you need to create a wrapper DLL that exports non-COM-based functions.

  • The DllImport attribute supports only the CharSet.Unicode and CharSet.Auto character sets.

  • The DllImport attribute supports only the CallingConvention.Winapi calling convention.

Sending an SMS Message from .NET

The following example shows a slightly more complicated way of using the Platform Invoke services. Because the Compact Framework does not support the marshaling of objects that are contained within a structure, you need to create a C++ “wrapper” library in order to call the Pocket PC Phone Edition’s SMS API functions (see Chapter 8).

First, create the wrapper library using Embedded Visual C++ 3.0. The code for the library will look as follows:

// First is the definition file for the DLL
// smsinvoke.def
   SendSMSInvokeMsg   @1

// Here is the wrapper DLL
// smsinvoke.cpp
#include <windows.h>
#include <sms.h>

#ifdef __cplusplus
extern "C" {
__declspec(dllexport) BOOL SendSMSInvokeMsg(TCHAR
  *tchPhoneNumber, TCHAR *tchMessage);
#ifdef __cplusplus

  LPVOID lpvReserved)
   return TRUE;

BOOL SendSMSInvokeMsg(TCHAR *tchPhoneNumber, TCHAR
  HANDLE hSmsEvent = NULL;
  HRESULT hr = S_OK;
  BOOL fReturn = FALSE;

  // Make sure we have a number and a message
  if(!tchPhoneNumber || !tchMessage)
     return fReturn;

  // Open up SMS

  if(FAILED(hr)) {
     OutputDebugString(TEXT("Could not open a handle to
        the SMS text message service."));
     return fReturn;

  // Wait for SMS to become signaled as ready
  DWORD dwReturn = 0;
  dwReturn = WaitForSingleObject(hSmsEvent, INFINITE);

  // SMS Event has become signaled
  if(dwReturn == WAIT_ABANDONED || dwReturn ==
     WAIT_TIMEOUT) {OutputDebugString(TEXT("No longer waiting for
     a message"));
     return fReturn;

  // Send an SMS Message through default SMSC
  SMS_ADDRESS smsDestination;
  SMS_MESSAGE_ID smsMsgId = 0;

  // Set the destination address for the message
  memset(&smsDestination, 0, sizeof(SMS_ADDRESS));
  smsDestination.smsatAddressType = SMSAT_INTERNATIONAL;
  _tcsncpy(smsDestination.ptsAddress, tchPhoneNumber,

  // Create the message
  DWORD dwMessageLength = 0;
  dwMessageLength = lstrlen(tchMessage)*sizeof(TCHAR);

  // Configure the Text Provider
  DWORD dwProviderLength = 0;

  memset(&txtProviderData, 0, sizeof(TEXT_PROVIDER_

   txtProviderData.dwMessageOptions =
   txtProviderData.psMessageClass = PS_MESSAGE_CLASS0;
   txtProviderData.psReplaceOption = PSRO_NONE;
   dwProviderLength = sizeof(TEXT_PROVIDER_SPECIFIC_DATA);

   // Send the message
   hr = SmsSendMessage(hSms, NULL, &smsDestination, NULL,
      (BYTE *)tchMessage, dwMessageLength, (LPBYTE)&txtProviderData,

      OutputDebugString(TEXT("Could not send SMS Text
   else {
      OutputDebugString(TEXT("Message has been sent."));
      fReturn = TRUE;

   return fReturn;

Second, use P/Invoke from C# to send an SMS by calling into the wrapper function, as follows:

using System;
using System.Data;
using System.Runtime.InteropServices;

namespace SmsInvokeTest {
   class Class1 {
      // Hook up to wrapper function
      [DllImport("smsinvoke.dll", EntryPoint=
         "SendSMSInvokeMsg", CharSet=CharSet.Unicode,

      static extern Int32 SendSmsMessage(string
         stPhoneNumber, string stMessage);

      static void Main(string[] args) {
         // Create a message, and send it via SMS
         string stPhone = "4254432273";
         string stMessage = "Hi there from the Compact
         int nResult = 0;

         nResult = SendSmsMessage(stPhone, stMessage);
  • + Share This
  • 🔖 Save To Your Account