Pocket PC and PInvoke

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

Field

Description

EntryPoint

The function name that you want to call into

CharSet

Specifies how the string arguments should be marshaled

CallingConvention

Specifies the calling convention to use when passing arguments

SetLastError

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            stText,            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 LIBRARY SMSINVOKE EXPORTS    SendSMSInvokeMsg   @1 // Here is the wrapper DLL // smsinvoke.cpp #include <windows.h> #include <sms.h> #ifdef __cplusplus extern "C" { #endif __declspec(dllexport) BOOL SendSMSInvokeMsg(TCHAR   *tchPhoneNumber, TCHAR *tchMessage); #ifdef __cplusplus } #endif BOOL WINAPI DllMain(HANDLE hinstDLL, DWORD dwReason,   LPVOID lpvReserved) {    return TRUE; } BOOL SendSMSInvokeMsg(TCHAR *tchPhoneNumber, TCHAR   *tchMessage) {   SMS_HANDLE hSms = NULL;   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   hr = SmsOpen(SMS_MSGTYPE_TEXT, SMS_MODE_SEND, &hSms,      &hSmsEvent);   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"));      SmsClose(hSms);      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,      SMS_MAX_ADDRESS_LENGTH);   // Create the message   DWORD dwMessageLength = 0;   dwMessageLength = lstrlen(tchMessage)*sizeof(TCHAR);   // Configure the Text Provider   TEXT_PROVIDER_SPECIFIC_DATA txtProviderData;   DWORD dwProviderLength = 0;   memset(&txtProviderData, 0, sizeof(TEXT_PROVIDER_      SPECIFIC_DATA));    txtProviderData.dwMessageOptions =       PS_MESSAGE_OPTION_STATUSREPORT;    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,       dwProviderLength, SMSDE_OPTIMAL, SMS_OPTION_DELIVERY_NONE,       &smsMsgId);    if(FAILED(hr))       OutputDebugString(TEXT("Could not send SMS Text          Message."));    else {       OutputDebugString(TEXT("Message has been sent."));       fReturn = TRUE;    }    SmsClose(hSms);    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,          SetLastError=true)]       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             Framework!";          int nResult = 0;          nResult = SendSmsMessage(stPhone, stMessage);       }    } } 


Pocket PC Network Programming
Pocket PC Network Programming
ISBN: 0321133528
EAN: 2147483647
Year: 2005
Pages: 90

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net