The desktop version of the .NET Framework is very rich. It includes classes capable of performing advanced windowing, graphics manipulation, network connectivity, and much more. The .NET Framework is nearly a platform of its own, insulating developers from needing to interact with the operating system below. The price of this power and programming convenience is a footprint too large for most devices running Windows CE. Users of the .NET Compact Framework can invoke the Windows CE operating system to perform actions that are out of reach by using the .NET Compact Framework alone. Situations where doing so would be useful include the following:
Calling the Windows CE operating system is no different from calling native code, as we have described in detail already. In order to call the Windows CE operating system, you need to follow these steps:
If you understand all of the previous sections of this chapter, then the real challenge is in steps 1, 2, and 4. To solidify the experience of calling the Windows CE operating system, a tutorial approach is used. The goal is to use the Windows CE API to play a .wav sound file. Calling the Windows CE API to Play a SoundThis section presents a tutorial that implements all four steps needed to call into the Windows CE operating system, as described in the preceding discussion. The goal of the tutorial is to play a .wav sound file. Determining Which Windows CE Function to CallThe Windows CE function for playing a .wav file is PlaySound() . You can learn all about PlaySound() by consulting the documentation included with Embedded Visual C++ 3.0. The PlaySound() function resides in coredll.dll . The function prototype, including descriptions of the input parameters, are described as follows : BOOL WINAPI PlaySound(LPCSTR pszSound, HMODULE hmod, DWORD fdwSound)
One question you may be asking is, How do you know the numeric values of the flags in managed code? In native code, for example, C++, you just need to include the appropriate header file and the flags as defined constants. That doesn't help if you need to know the values for use from managed code. You may find these values in the documentation. For the constants SND_LOOP and SND_ASYNC , there were no such values in the documentation. Thus, for the tutorial, it was necessary to create a simple application called ConstFinder by using Embedded Visual C++ 3.0. In this C++ application, the constant values SND_LOOP and SND_ASYNC were assigned into DWORD variables . Then, it is easy to use the debugger to step through the code and examine the values and find that SND_LOOP = 8 and SND_ASYNC = 1 . Now one can use these numeric values within managed code and pass them into the PlaySound() function from managed code. You can find the PlaySound ConstFinder project in the directory \SampleApplications\Chapter12\ PlaySound_ConstFinder . Creating the Managed Code Declaration for PlaySoundThe next step is to create a managed code declaration for the PlaySound function. The following declaration displays this code: C# [DllImport "coredll.dll"] private static extern bool PlaySound(string pszSound, IntPtr hmod, uint fdwSound); VB Declare Sub PlaySound Lib "coredll.dll" ( ByVal pszSound As String, ByVal hmod As IntPtr, ByVal fdwSound As UInt32) Calling the Native PlaySound FunctionNow call the function as appropriate. The following code sample plays the "\ASound.wav" sound file once. The function blocks until the sound has been played. C# IntPtr l_NULL = IntPtr.Zero; PlaySound("\ASound.wav", l_NULL, 0); VB Dim l_NULL As IntPtr = IntPtr.Zero PlaySound("\Asound.wav", l_NULL, Convert.ToUInt32(0)) The following code sample plays the "\ASound.wav" file continuously. The function returns immediately, even as the sound plays in the background. The calling thread sleeps for five seconds, and then another call to PlaySound() stops the sound from playing. C# const int SND_LOOP = 8; const int SND_ASYNC = 1; IntPtr l_NULL = IntPtr.Zero; PlaySound("\ASound.wav", l_NULL, SND_LOOP + SND_ASYNC); System.Threading.Thread.Sleep(5000); PlaySound(null, l_NULL, 0); VB Const SND_LOOP As Integer = 8 Const SND_ASYNC As Integer = 1 Dim l_NULL As IntPtr = IntPtr.Zero PlaySound("\ASound.wav", l_NULL, Convert.ToUInt32(SND_LOOP + SND_ASYNC)) System.Threading.Thread.Sleep(5000) PlaySound(Nothing, l_NULL, Convert.ToUInt32(0)) Putting It All Together with a Sample Application: PlaySoundThe PlaySound sample application is available in the folder \SampleApplications\Chapter12 , where there are C# and Visual Basic versions. The PlaySound application is a complete implementation of the issues tackled in the previous tutorial. To use it, build, deploy, and launch it on a device. The application shows a form with a text box in which you can enter the path to a WAV file to play. The default value is a WAV file included with the Pocket PC version of Windows CE. To play the sound just once, click the button labeled Play Sound Once. The application calls the native PlaySound function in synchronous mode. The main thread of the managed application blocks until the sound is finished being played. To play a sound continuously, click the button labeled Play Sound Continuously. The application plays the sound by calling the Windows CE API function, PlaySound() , passing arguments to play the sound in a loop asynchronously. The Play Sound Continuously button's label changes to Stop Playing Sound!!!, and the managed application's main thread remains responsive , even as the sound plays. Click the button relabeled Stop Playing Sound!!! to stop playing the sound. The managed application responds by calling PlaySound() again with a NULL value for the sound file name argument. This causes the sound to stop playing. This sample application helps illustrate an important point when calling Windows CE functions: Pay attention to whether the function returns immediately and how long the function will take to execute. It is easy to accidentally call a function that performs some sort of I/O in blocking mode and ties up the managed thread that makes the native call for a long time. If you call the function from the main managed thread, then your application will stop responding to user input for a potentially long time. In such cases, consider spinning off a new thread to call the Windows CE operating system. Chapter 4, "Using Threads and Timers in the .NET Compact Framework," describes threading in great detail. |