Export (0) Print
Expand All

Step by Step: Incorporating COM Objects into Your .NET Compact Framework 2.0 Application

.NET Compact Framework 1.0
 

Microsoft Corporation

June 2006

Applies to:
   Microsoft Visual Studio 2005
   Microsoft .NET Compact Framework 2.0
   Windows Mobile version 5.0 software for Pocket PCs

Summary: Learn how the Microsoft .NET Compact Framework version 2.0 enables you to more easily incorporate your existing native COM objects into your managed applications. This HOL will take 1 hour and 15 minutes to complete. (50 printed pages)


Download MEDC06_HOL301.msi from the Microsoft Download Center.

Contents

Introduction
Lab 1: Incorporating COM Objects into Your .NET Compact Framework 2.0 Application
Summary
Appendix A. Terminating an Application That Is Running on a Device or Emulator
Appendix B: Setting Up Your Computer

The following applications are required to run this HOL:

Introduction

In this HOL, you will learn how the Microsoft .NET Compact Framework version 2.0 enables you to more easily incorporate your existing native COM objects into your managed applications. Through a series of examples, you will learn how to prepare your COM objects, incorporate them into your .NET Compact Framework projects, and call them from managed code. Upon completion of this HOL, you will know how to avoid rewriting all of your legacy COM objects by using them directly in your .NET Compact Framework applications.

Lab 1: Incorporating COM Objects into Your .NET Compact Framework 2.0 Application

In this lab, you will learn how you can use the .NET Compact Framework version 2.0 to incorporate your existing native COM objects into managed applications. Through a series of examples, you will learn how to prepare your COM objects, incorporate them into your .NET Compact Framework projects, and call them from managed code. Upon completion of this lab, you will know how to avoid rewriting all of your legacy COM objects by using them directly in your .NET Compact Framework applications.

Because completing all exercises in the lab may take more time than you have available, you may select only those exercises that are most useful for you. Each exercise starts with a completely new project, and there is no explicit order in which you have to do the exercises.

In this lab, you will perform the following exercises:

  • Creating and using a COM object by using Visual Studio 2005
  • Accessing Pocket Outlook inside a managed application
  • Accessing Pocket Outlook by using Windows Mobile 5.0 managed APIs

Exercise 1: Creating and Using a COM Object by Using Visual Studio 2005

In this exercise, you will create a COM object that you will use from within a .NET Compact Framework 2.0 application. This exercise is the starting point for this section of the HOL, in which you will build a complete Pocket PC application through a number of exercises. As you will find out, you can use Visual Studio 2005 to create managed .NET Compact Framework applications and native C++ applications for devices—even with ATL or MFC support.

To open an existing solution and add a new project to it

  1. On the desktop computer, click Start | All Programs | Microsoft Visual Studio 2005 | Microsoft Visual Studio 2005.
  2. In Visual Studio 2005, click File | Open | Project/Solution.
  3. In the Open Project dialog box, browse to C:\Program Files\Windows Mobile Developer Samples\HOLs\MEDC06_HOL301\HOL301Exercise1.
  4. Select HOL301Exercise1.sln, and then click Open. The solution opens.
  5. In Solution Explorer, right-click Solution 'HOL301Exercise1' (1 project), and then select Add | New Project to add a new project to the solution.
  6. In the Add New Project dialog box under Project types, ensure that Other Languages | Visual C++ | Smart Device is selected.
    Note   Depending on your Visual Studio configuration, the Visual C++ project type may be located at the outer-most outline level instead of under Other Languages.
  7. Under Templates, ensure ATL Smart Device Project is selected.
  8. In the Name box, change the name to MyCOMObject, as shown in Figure 1.

    Click here for larger image

    Figure 1. Add New Project dialog box. Click the thumbnail for a larger image.

  9. Click OK to start the ATL Smart Device Project Wizard.

    The wizard is going to assist you in creating your COM object. You need to provide some basic information, but you can leave most of the settings as they are.

  10. On the welcome page of the wizard, click Next.
  11. On the Platforms page of the ATL Smart Device Project Wizard, as shown in Figure 2, be sure that only Windows Mobile 5.0 Pocket PC SDK is listed under Selected SDKs. Use the add and remove arrow buttons to move the appropriate SDKs.

    Click here for larger image

    Figure 2. Platforms page of the ATL Smart Device Project Wizard. Click the thumbnail for a larger image.

  12. Click Next.
  13. On the Application Settings page of the ATL Smart Device Project Wizard, be sure that Dynamic-link library (DLL) is selected under Server type, and be sure that the additional options boxes are not selected.
  14. Click Finish to exit the wizard.

    The wizard has created a new project called MyCOMObject that contains all of the code to act as a COM component. To turn this project into a meaningful COM object, you have to add functionality for your specific COM object.

To add a new class to the COM object

  1. In Solution Explorer, right-click the MyCOMObject project, point to Add, and then click Class.

    (Alternatively, you can click Project | Add Class from the Visual Studio 2005 menu.)

  2. In the Add Class dialog box, in the Categories tree, select ATL, and be sure that ATL Simple Object is selected in the list of available templates, as shown in Figure 3.

    Click here for larger image

    Figure 3. Add Class dialog box. Click the thumbnail for a larger image.

  3. Click the Add button.

    The ATL Simple Object Wizard starts. In this wizard, you will give your new object a name and set some specific object settings.

  4. On the left side of the Welcome to the ATL Simple Object Wizard page, select Names.
  5. In the C++ Short name box, type SimpleCalc. Leave all of the other values as default, as shown in Figure 4.

    Click here for larger image

    Figure 4. Names page of the ATL Simple Object Wizard. Click the thumbnail for a larger image.

  6. Click Next.
  7. On the Options page of the ATL Simple Object Wizard, under Threading model, select Free.
  8. Under Interface, select Custom, as shown in Figure 5.

    Click here for larger image

    Figure 5. Options page of the ATL Simple Object Wizard. Click the thumbnail for a larger image.

  9. Click Finish to close the wizard and create the new class.

    The ATL Simple Object Wizard has created a number of new files for you, in which you will add methods and interfaces that bring functionality to your COM object. The COM object that you are about to implement contains a few basic math functions, like add, subtract, multiply, and divide. The functionality is straightforward, but it should help you understand how a managed .NET Compact Framework application can interoperate with a COM object.

You will now work on the implementation of SimpleCalc. All methods that you are going to write will be exposed through COM interfaces. A COM client can access the methods and, thanks to COM Interop, a managed client application can access SimpleCalc's methods (as you will see in this HOL).

To implement the functionality of SimpleCalc

  1. In Visual Studio 2005, change to Class View by clicking View | Class View or by using the keyboard shortcut CTRL+W+C.
  2. In the Class View pane, expand MyCOMObject, right-click the interface ISimpleCalc, and then select Add | Add Method, as shown in Figure 6.

    The Add Method Wizard appears. In this wizard, you will specify the signature of the method that you are going to add.

    Click here for larger image

    Figure 6. Adding a method to ISimpleCalc. Click the thumbnail for a larger image.

  3. In the Add Method Wizard, type Add in the Method name box.
  4. Type int in the Parameter type box.
  5. Type iFirstValue in the Parameter name box.
  6. Select the in check box under Parameter attributes.
  7. Click the Add button.
  8. Type int in the Parameter type box.
  9. Type iSecondValue in the Parameter name box.
  10. Select the in check box under Parameter attributes.
  11. Click the Add button.
  12. Type int* in the Parameter type box.
  13. Type piResult in the Parameter name box.
  14. Select the retval check box under Parameter attributes.
  15. Click the Add button.

    The Add Method Wizard's Names page should now look like Figure 7.

    Click here for larger image

    Figure 7. Names page of the Add Method Wizard. Click the thumbnail for a larger image.

  16. Click Finish.

    You have just created a new empty method with a COM interface. You can find the method's interface in the header file SimpleCalc.h, the (still empty) implementation in the source file SimpleCalc.cpp. Next, you will add a few more methods to the component. You will also automatically see the new methods appear in the Class View pane.

  17. In the Class View pane, right-click the interface ISimpleCalc, and then click Add | Add Method.
  18. Type Subtract in the Method name box.
  19. Repeat Steps 4 through 16 to add parameters to the method. You must enter exactly the same parameters.
  20. Repeating the same steps, add a new method called Multiply.
  21. Again, repeating the same steps, add a new method called Divide.

    The only thing left to do to finish your COM component is add functionality.

  22. In Solution Explorer, (View | Solution Explorer View), open the file SimpleCalc.cpp by double-clicking it. You can find this file under Source Files.
  23. Find the method CSimpleCalc::Add, and then add the following statement to the method (prior to the statement return S_OK).
    *piResult = iFirstValue + iSecondValue;
    
    
  24. Find the method CSimpleCalc::Subtract, and then add the following statement to the method (prior to the statement return S_OK).
    *piResult = iFirstValue - iSecondValue;
    
    
  25. Find the method CSimpleCalc::Multiply, and then add the following statement to the method (prior to the statement return S_OK).
    *piResult = iFirstValue * iSecondValue;
    
    
  26. Find the method CSimpleCalc::Divide, and then replace all of its code with the following code example.
    if (iSecondValue != 0)
    {
        *piResult = iFirstValue / iSecondValue;
        return S_OK;
    }
    else
    {
        *piResult = 0;
        return E_FAIL;
    }
    
    
  27. Compile the COM object by clicking Build | Build Solution or by pressing F6.

    Assuming you didn't get any compilation errors, you are now going to use the COM object inside a managed application.

To use the COM object inside a managed application

  1. In Solution Explorer, browse to the project ManagedCOMClient, and then expand it (if it is not expanded already).
  2. Open the file Form1.cs in the form designer by double-clicking it in Solution Explorer.

    To save time, the user interface is already created for you, which should look like Figure 8.

    Click here for larger image

    Figure 8. User interface for ManagedCOMClient. Click the thumbnail for a larger image.

    The next thing you will do is add functionality to the application to make use of MyCOMObject. Before you can use the COM component, you have to add a reference to it to make it available in the managed application. When you are adding a reference to a COM object, code is automatically generated by Visual Studio 2005 to be able to use your COM object inside a managed application.

    You need a so-called Interop Assembly to be able to call into a COM object. The Interop Assembly contains managed definitions of COM interfaces and types. It can be generated manually by the Type Library Importer (tlbimp.exe), or it can be generated automatically by Visual Studio 2005 when you add a reference to the COM object's Type Library (*.tlb) file, which you will see in a moment. To a managed client application, the COM object looks like a managed type, as shown in Figure 9. The Runtime Callable Wrapper hides all COM details for you.

    Click here for larger image

    Figure 9. Calling a COM component from a managed client. Click the thumbnail for a larger image.

    To generate an Interop Assembly to be able to access the COM component from within managed code, you need to add a reference to MyCOMObject.tlb.

  3. In Solution Explorer, right-click References, and then click Add Reference to add a reference to the ManagedCOMClient project.
  4. In the Add Reference dialog box, click the Browse tab, and then browse to MyCOMObject.tlb in C:\Program Files\Windows Mobile Developer Samples\HOLs\MEDC06_HOL301\HOL301Exercise1\MyCOMObject\Windows Mobile 5.0 Pocket PC SDK (ARMV4I)\Debug.
    Note   You can easily browse to the type library file by clicking the Up One Level button on the toolbar of the Add Reference dialog box, after which you can browse through the MyCOMObject project tree to reach the MyCOMObject.tlb file.
  5. Click OK to add the selected reference to the project.

    You can now use the methods from MyCOMObject as if it were a managed object, as you will see when you are adding functionality to the button click event handlers of the ManagedCOMClient application.

  6. In Solution Explorer, right-click Form1.cs, and then click View Code.
  7. Create an alias for the "System.Runtime.InteropServices" namespace by adding the following statement immediately under the other using statements at the beginning of the Form1.cs file (this is the file into which all other code will be added as well).
    using System.Runtime.InteropServices;
    
    
  8. Create an alias for your COM component by adding the following statement.
    using MyCOMObjectLib;
    
    
  9. Add the following instance variable to the Form1 class.
    private ISimpleCalc calculator = new SimpleCalc();
    
    

    You now have declared an interface variable of type ISimpleCalc and instantiated it with a SimpleCalc object. This is, in fact, an instantiation of your COM component.

  10. Add the following code to the btnAdd_Click event handler.
    int firstValue = Convert.ToInt32(tbValue1.Text);
    int secondValue = Convert.ToInt32(tbValue2.Text);
    int result = calculator.Add(firstValue, secondValue);
    tbResult.Text = result.ToString();
    
    

    As you saw when entering the Add method for the calculator, it looks like a managed object and even has full Microsoft IntelliSense support. If you compare the managed call to the Add method as defined in the COM component, you will see a remarkable difference.

    The signature of the managed Add method looks like the following.

     int Add (int iFirstValue, int iSecondValue);
    
    

    The signature of the COM Add method looks like the following.

      HRESULT Add ([in]int iFirstValue,
                                            [in]int iSecondValue, 
                                            [out, retval]int* piResult);
    
    

    The translation of the COM method to the managed method happened automatically when you added a reference to the Type Library file.

  11. Add the following code to the btnSubtract_Click event handler.
    int firstValue = Convert.ToInt32(tbValue1.Text);
    int secondValue = Convert.ToInt32(tbValue2.Text);
    int result = calculator.Subtract(firstValue, secondValue);
    tbResult.Text = result.ToString();
    
    
  12. Add the following code to the btnMultiply_Click event handler.
    int firstValue = Convert.ToInt32(tbValue1.Text);
    int secondValue = Convert.ToInt32(tbValue2.Text);
    int result = calculator.Multiply(firstValue, secondValue);
    tbResult.Text = result.ToString();
    
    
  13. Add the following code to the btnDivide_Click event handler.
    int firstValue = Convert.ToInt32(tbValue1.Text);
    int secondValue = Convert.ToInt32(tbValue2.Text);
    int result = calculator.Divide(firstValue, secondValue);
    tbResult.Text = result.ToString();
    
    
  14. Compile the entire solution, including the code that you just entered by clicking Build | Build Solution or by pressing F6.

    Assuming you didn't get compilation errors, you can now test the ManagedCOMClient application in the Windows Mobile 5.0 Pocket PC emulator.

To test the ManagedCOMClient application in the emulator

  1. In Visual Studio 2005, press F5 or select Debug | Start Debugging to start the application in debugging mode.
  2. In the Deploy ManagedCOMClient dialog box, be sure that the Windows Mobile 5.0 Pocket PC Emulator is selected, and then click the Deploy button.
    Note   If you receive an error during deployment that indicates that the process or file is in use, this means that the program is still running on the emulator and must be closed before a new copy can be deployed and run. This error may appear anytime in the lab that you deploy the emulator. See Appendix A in this HOL for instructions about exiting a running application.
  3. Be sure that the emulator is visible by clicking its button in the Windows taskbar.

    After a while, you will see the application running inside the Windows Mobile 5.0 Pocket PC emulator. Now it is time to test the application. It may take some time to deploy the application for the first time. The first time you are using the emulator, prior to deploying the application, the .NET Compact Framework 2.0 will be deployed to the emulator as well. When the .NET Compact Framework 2.0 is already found on the emulator, this step is skipped.

  4. Enter different numbers in the text boxes for Value1 and for Value2.
  5. Click all four buttons one after another, and examine the result. Every time a button is clicked, a method in the COM object is called. The running application should look like Figure 10.

    Figure 10. ManagedCOMClient application running in the emulator

  6. Enter the number 0 in the Value2 box, and then click the divide button. You will see an exception being thrown, as shown in Figure 11.

    Click here for larger image

    Figure 11. Exception that is thrown from the divide method call. Click the thumbnail for a larger image.

    This is the default behavior when a method call of a COM object returns a value other than S_OK as HRESULT. Therefore, it is always advisable to add exception handling when calling into COM objects.

  7. Stop the debugger by clicking Debug | Stop Debugging.
  8. Change the code for the btnDivide_Click event handler in source file Form1.cs to the following.
    int firstValue = Convert.ToInt32(tbValue1.Text);
    int secondValue = Convert.ToInt32(tbValue2.Text);
    try
    {
        int result = calculator.Divide(firstValue, secondValue);
        tbResult.Text = result.ToString();
    }
    catch
    {
        tbResult.Text = "Undefined";
    }
    
    
  9. In Visual Studio, press F5 or click Debug | Start Debugging to start the application in debugging mode.
  10. In the Deploy ManagedCOMClient dialog box, be sure that the Windows Mobile 5.0 Pocket PC Emulator is selected, and then click the Deploy button.
  11. Watch what happens if you enter the number 0 in the Value2 box and then click the divide button (at least the behavior is now much more acceptable, simply by adding an exception handler), as shown in Figure 12.

    Figure 12. The application continues to run when attempting to divide by zero

  12. Close the application by clicking the ok button in the upper-right corner of the application.

In the .NET Compact Framework 2.0, it is not only possible to call methods on COM components without the need to write your own wrapper. It is also possible to call back from the COM object into the managed client, thanks to the fact that the .NET Compact Framework 2.0 also allows calling from native to managed code.

You will now extend MyCOMObject by adding a new interface and implementing callback functionality. The callback functionality that you are implementing simply displays a message passed from the COM component to a managed message box. Note that even though callbacks are supported, activation of .NET types from COM is not supported.

To callback from COM into the managed client

  1. In Solution Explorer, double-click the MyCOMObject.idl to open it. You can find the file in the tree view by clicking MyComObject | Source Files.
  2. In the MyCOMObject.idl file, look for the definition of the line import atliface.idl, and then manually add a new interface immediately below it. Enter the following code for the new interface.
    [
      object,
      uuid(),
      helpstring("ISimpleCalcCallBack Interface"),
      pointer_default(unique)
    ]
    interface ISimpleCalcCallBack : IUnknown{
      [, helpstring("method ShowMsg")] HRESULT ShowMsg([in] LPTSTR pMsg);
    };
    
    
  3. Add a new universally unique identifier (UUID) to the interface to distinguish it from other interfaces. (You can generate a UUID in Visual Studio 2005 by clicking Tools | Create GUID.)
  4. In the Create GUID dialog box, be sure that the Registry Format option is selected, as shown in Figure 13.

    Figure 13. Generating a new GUID to identify the newly created interface

  5. Click New GUID, and then immediately click Copy.
  6. Click Exit to close the Create GUID dialog box.
  7. In MyCOMObject.idl, place the cursor between the brackets behind the UUID attribute in the code that you just entered, and then paste the created GUID in there. Be sure to remove the braces that were copied as part of the GUID.
  8. Verify that the interface you added in the MyCOMObject.idl file, including the GUID you pasted in it, looks like the following.
    [
      object,
      uuid(54BE93A8-84F3-424a-AE3F-04A6EA833BD5),
      helpstring("ISimpleCalcCallBack Interface"),
      pointer_default(unique)
    ]
    interface ISimpleCalcCallBack : IUnknown{
       [, helpstring("method ShowMsg")] HRESULT ShowMsg([in] LPTSTR pMsg);
    };
    
    
    Note   The value of the GUID that you pasted in differs from the value that you see in this example. You have just created a new interface for your COM component, and this interface contains only one method called ShowMsg. This is the only method that the ISimpleCalcCallBack interface exposes. This method acts as the callback from managed code, so you will write the implementation for this particular interface later in managed code. First, however, you need to do something else. To store the callback function in the COM object, you have to pass a reference to it from managed code. Therefore, you will add another method to the ISimpleCalc interface.
  9. In the Class View pane, right-click the interface ISimpleCalc, and then select Add | Add Method.

    This step displays the Add Method Wizard, in which you will specify the signature of the method you are going to add.

  10. Type Initialize in the Method name box.
  11. Type ISimpleCalcCallBack* as the Parameter type.
  12. Type callbackInterface in the Parameter name box.
  13. Select the in check box under Parameter attributes.
  14. Click the Add button, and then click the Finish button.

    You have now created all interfaces, but to be able to use the callback function, you also have to implement the Initialize method.

  15. In Visual Studio 2005, in Solution Explorer, double-click SimpleCalc.cpp to open it. You can find this file under Source Files.
  16. Find the CSimpleCalc::Initialize method, and then add the following code to the method (prior to the statement return S_OK).
    pClientCallback = callbackInterface;
    
    // Because you are using a new interface for the first time, be
    // sure to increment its reference count.
    pClientCallback->AddRef();
    
    // and callback into managed code for the first time
    pClientCallback->ShowMsg(_T("Managed Callback installed!"));
    
    
  17. Find the CSimpleCalc::Divide method, and then add the following code to the method to give the user an error message. Add the code prior to the statement return E_FAIL.
    if (pClientCallback)
        pClientCallback->ShowMsg(_T("Oops, you should not divide by zero!"));
    
    

    As you can see in the code for the Initialize method, the callback method is stored locally. However, you still need to declare a variable to store the callback method into. Finally, you are also providing some code to release the interface after you finish with the object.

  18. In Solution Explorer, double-click SimpleCalc.h to open it. You can find this file under Header Files.
  19. Add the following code toward the end of the CSimpleCalc class.
    private:
        ISimpleCalcCallBack* pClientCallback;
    
    
  20. In the SimpleCalc.h header file, look for the FinalRelease method inside the CSimpleCalc class, and then add the following code to the method.
    if (pClientCallback)
        pClientCallback->Release();
    
    
  21. Compile the COM component that you just extended by clicking Build | Build Solution, or by pressing F6.

    Before you can use the callback functionality that you just have implemented, you need to provide the COM component with a managed function that can act as a callback. You will create the callback method as part of a new class that you will now add to the ManagedCOMClient project.

  22. In Solution Explorer, right-click the project ManagedCOMClient, and then select Add | Class.
  23. In the Add New Item dialog box, be sure that Class is selected in the Templates list.
  24. Change the name of the class to NewMsgNotification.cs, and then click the Add button.
  25. Replace all of the code in the NewMsgNotification.cs source file that you just created with the following code.
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Windows.Forms;
    using System.Runtime.InteropServices;
    using MyCOMObjectLib;
    
    namespace ManagedCOMClient
    {
        public class NewMsgNotification : ISimpleCalcCallBack
        {
            public void ShowMsg(string message)
            {
                MessageBox.Show(message);
            }
        }
    }
    
    

    As you can see, the NewMsgNotification class derives from the ISimpleCalcCallBack interface, which is the interface that you created in the COM component. The interface expects one function, called ShowMsg, that is defined in the class as well. Finally, you need to connect the callback function to the COM component.

  26. In Code view, open the Form1.cs source file in Visual Studio 2005.
  27. Add an instance variable for the new class that you just created by adding the following code.
    private NewMsgNotification newMsg = new NewMsgNotification();
    
    
  28. Find the constructor of the Form1 class, and then add a call to the Initialize method of the calculator COM object to tell the COM object what callback function to use (add the following statement immediately under InitializeComponent()):
    calculator.Initialize((ISimpleCalcCallBack)newMsg);
    
    
  29. In Visual Studio, press F5 or click Debug | Start Debugging to start the application in debugging mode.
  30. In the Deploy ManagedCOMClient dialog box, be sure that the Windows Mobile 5.0 Pocket PC Emulator is selected, and then click the Deploy button.

    After a while, you will see the application running inside the Windows Mobile 5.0 Pocket PC emulator. Immediately, you will notice that a message appears and informs you that the managed callback is installed, as shown in Figure 14.

    Click here for larger image

    Figure 14. Managed callback installation dialog box. Click the thumbnail for a larger image.

    This message box resides inside managed code (in the newly created class), but it is called from inside the COM component. Now, watch what happens if you divide by zero.

  31. Click ok to close the message.
  32. Type 1 in the Value1 box, and then type 0 for Value2.
  33. Click the divide button, and verify that another message appears, as shown in Figure 15.

    Figure 15. The divide by zero message

  34. Click ok to close the message, and then close the application by clicking the ok button in the upper-right corner of the application.

This step concludes the first exercise. You have created a COM component by using ATL and used that component inside a managed client application. Not only is it possible to call methods in the COM component from inside managed code, but it is also possible to register a managed callback function in the COM component. As you just have seen, it is very simple to access COM components from within managed code—without the need to write your own wrapper—as was the case in the .NET Compact Framework version 1.0. In the next exercise, you will use a popular, existing COM component inside a managed application.

Exercise 2: Accessing Pocket Outlook Inside a Managed Application

In this exercise, you will create a new Windows Mobile 5.0–based Pocket PC application that makes use of Microsoft Office Outlook Mobile by means of the Pocket Outlook Object Model (POOM). POOM is a COM component that exposes functionality of Pocket Outlook, so you can use that functionality in your own (managed) application. In the .NET Compact Framework 1.0, using POOM was not straightforward. You had to either create a wrapper DLL in native code that flattens out the POOM component or make use of a third-party library that did exactly this for you. With the .NET Compact Framework 2.0, it is much easier to use POOM inside a managed application, thanks to COM Interop. In this exercise, you are not going to create a fancy user interface; instead, you will concentrate on the possibilities that POOM offers.

To open an existing solution and add functionality to it

  1. If it is not already running, open Visual Studio 2005.
  2. In Visual Studio 2005, click File | Open | Project/Solution.
  3. In the Open Project dialog box, browse to C:\Program Files\Windows Mobile Developer Samples\HOLs\MEDC06_HOL301\HOL301Exercise2.
  4. Select the HOL301Exercise2.sln file, and then click Open. The solution opens in Visual Studio 2005.

    The entire user interface is already created for you to save some time. In this exercise, you will add functionality to the application to access Pocket Outlook functionality.

To use the POOM in your managed application, you don't have to write numerous platform invoke wrappers or define your own managed object model. Instead, you can generate an assembly by using the Type Library Importer (tlbimp.exe) SDK tool, so you can call POOM directly. You will now create a POOM type library. From that, you will create an Interop Assembly, and you will reference that Interop Assembly in your Visual Studio 2005 project.

The easiest way to call a COM component from managed code is to start with a type library that defines the component's interfaces, coclasses, and so on. Unfortunately, the type library for POOM is not included in the Pocket PC or Smartphone SDKs, so you'll have to build your own. Fortunately, building the type library is easy.

To make POOM work with your Pocket PC application

  1. On the desktop computer, click Start | All Programs | Microsoft Visual Studio 2005 | Visual Studio Tools | Visual Studio 2005 Command Prompt to open a Visual Studio 2005 command prompt.
    Note   It is important to use this particular command prompt because it sets a number of environment variables, so you can use particular command-line tools that come with Visual Studio 2005.
  2. In the Command Prompt window, type cd "C:\Program Files\Windows Mobile Developer Samples\HOLs\MEDC06_HOL301\HOL301Exercise2" to change the working directory, and then press ENTER.

    Now you will create a type library for POOM by using midl.exe. You typically need to execute this step for all COM components that you want to access from inside a managed application and that don't have a type library available. You need to have the interface definition file for that particular COM component.

    Note   Pimstore.idl does not ship with the Windows Mobile 5.0 Pocket PC SDK. The file is included in the source code for this HOL in the folder specified in step 2.
  3. In the Command Prompt window, type midl pimstore.idl, and then press ENTER, which creates a type library for POOM.

    Executing this command creates a type library file for you with the name pimstore.tlb. You can simply ignore the warnings that the tool may generate. The next step is to reference pimstore.tlb from within Visual Studio.

  4. Close the Command Prompt window.

    To generate an Interop Assembly to be able to access POOM from within managed code, you now need to add a reference to pimstore.tlb.

  5. In Solution Explorer under the project UsingPOOM, right-click References, and then click Add Reference.
  6. In the Add Reference dialog box, click the Browse tab, and then browse to C:\Program Files\Windows Mobile Developer Samples\HOLs\MEDC06_HOL301.
  7. Select pimstore.tlb.
    Note   You can easily browse to the type library file by clicking the Up One Level button on the toolbar of the Add Reference dialog box.
  8. Click OK to generate the Interop Assembly.
  9. If you expand the References tree in Solution Explorer, you will find a newly added reference to PocketOutlook, the just-created Interop Assembly that is your managed interface to POOM, as shown in Figure 16.

    Click here for larger image

    Figure 16. PocketOutlook reference to pimstore.tlb. Click the thumbnail for a larger image.

To be able to use POOM inside your managed application, you need to add a number of namespaces. You also need to create an instance to the Pocket Outlook application and log on to it. Because you are going to use POOM all through your application, you will create the instance to the application and log on to it when loading the main form. You will log off from the Pocket Outlook application when the main form is closed. You can use POOM functionality throughout the lifetime of the application.

To access POOM inside your Pocket PC application

  1. In Solution Explorer, right-click Form1.cs, and then click View Code.
  2. Create an alias for the "System.Runtime.InteropServices" namespace by adding the following statement immediately under the other using statements at the beginning of the Form1.cs file (this is the file into which all other code will be added as well).
    using System.Runtime.InteropServices;
    
    
  3. Create an alias for POOM by adding the following statement.
    using PocketOutlook;
    
    
  4. Add the following instance variable to the Form1 class.
    private ApplicationClass outlookApp;
    
    
  5. In Solution Explorer, double-click Form1.cs to open Form1.cs [Design].
  6. Click somewhere on the form outside the controls, and then in the Properties pane, click the Events button on the toolbar.
  7. Look for the Load event and double-click it. You now have created a Form1_Load event handler.
  8. In the Form1_Load event handler, add the following code.
    // Create an instance of the application object and log on
    outlookApp = new PocketOutlook.ApplicationClass();
    outlookApp.Logon(0);
    
    
  9. Open Form1.cs [Design] again, and then click somewhere on the form outside the controls. In the Properties pane, click the Events button on the toolbar.
  10. Look for the Closing event and double-click it. You now have created a Form1_Closing event handler.
  11. In the Form1_Closing event handler, add the following code.
    outlookApp.Logoff();
    
    

    Now you should be able to use Pocket Outlook functionality in your own application, so this is a great time to test whether it is possible to create an instance of the Pocket Outlook application object and to log on to it and log off from it.

  12. In Visual Studio 2005, press F5 or click Debug | Start Debugging to start the application in debugging mode.
  13. In the Deploy UsingPoom dialog box, be sure that the Windows Mobile 5.0 Pocket PC Emulator device is selected, and then click the Deploy button.

    After a while, you will see the application running inside the Windows Mobile 5.0 Pocket PC emulator.

  14. While the application is running, find the Form1_Closing method in the Form1.cs file, and then set a breakpoint on the statement outlookApp.Logoff(). (Right-click the statement, point to Breakpoint, and then click Insert Breakpoint.)
  15. Click ok in the upper-right corner of the application inside the emulator.

    The debugger stops the application on the breakpoint, and inside Visual Studio 2005, you can examine variables.

  16. In Visual Studio 2005, expand the outlookApp object in the Autos pane. The contents of outlookApp should look similar to Figure 17.

    Click here for larger image

    Figure 17. Examining the contents of outlookApp in the Visual Studio 2005 debugger. Click the thumbnail for a larger image.

  17. Right-click the red circular breakpoint symbol to the left of the line of code with the breakpoint, and then click Delete Breakpoint.
  18. Continue running the application by pressing F5 to allow the application to close properly.

    Before you can do anything useful with the application, you have to add a few contacts in Pocket Outlook on the emulator.

  19. Be sure the Windows Mobile 5.0 Pocket PC emulator is visible, and then click Start | Contacts in the emulator.
  20. In the emulator, click New, and then add a few new contacts. Enter only names for contacts, and then click ok, as shown in Figure 18.

    Figure 18. Adding a new contact on the emulator

    Now, you will write some code for the UsingPOOM application to show the contacts that you have just added in Pocket Outlook in the list box inside your application. You are going to fill the list box with contacts from Pocket Outlook in the Form1_Load event handler.

  21. Find the Form1_Load method inside the Form1.cs file, and then add the following code to it, immediately under the statement outlookApp.Logon(0).
    ShowContacts();
    
    
  22. Add a new method called ShowContacts to the Form1.cs file with the following code.
    private void ShowContacts()
    {
        // Fill the list box with contact information from Pocket     // Outlook
        Folder contactsFolder = 
            outlookApp.GetDefaultFolder(OlDefaultFolders.olFolderContacts);
        PocketOutlook.Items contacts = (PocketOutlook.Items)contactsFolder.Items;
        listBox1.BeginUpdate();
        listBox1.Items.Clear();
        foreach (ContactItem contact in contacts)
        {
            string name = contact.FirstName + " " + contact.LastName;
            listBox1.Items.Add(name);
        }
        listBox1.EndUpdate();
    }
    
    

    The code you've just entered retrieves the folder in which Pocket Outlook stores contacts and walks through the contact's Items collection to add contact names to the list box. If you have added some contacts in Pocket Outlook and you run the UsingPOOM application, you will see those contacts appear in the list box.

  23. In Visual Studio, press F5 or click Debug | Start Debugging to start the application in debugging mode.
  24. In the Deploy UsingPoom dialog box, be sure that the Windows Mobile 5.0 Pocket PC Emulator is selected, and then click the Deploy button.
  25. After verifying that the contacts are visible in the list box, as shown in Figure 19, you can close the application again by clicking the ok button on the upper-right side of the form.

    Figure 19. Viewing Pocket Outlook contact names in the UsingPOOM application

To extend the application's functionality

  1. In Visual Studio's form designer, double-click each of the buttons on Form1 to add Click event handlers.
    Note   You have to switch back and forth between Code view and form designer to add click event handlers for all buttons.
  2. In the form designer, open the ContactDetails.cs file.
    Note   The ContactDetails.cs form already contains all user interface controls that you need, but the form does not yet contain any functionality.
  3. Add TextChanged event handlers for each of the text boxes. (To add TextChanged event handlers, click the text box, find the TextChanged event in the Properties pane (you have to click the Events button to see all of the available events), and then double-click it.)
    Note   You have to switch back and forth between Code view and the form designer to add click event handlers for all text boxes.
  4. In ContactDetails.cs [Design], click somewhere on the form outside the controls, and then in the Properties pane, click the Events button on the toolbar.
  5. Look for the Load event and double-click it.
  6. In the form designer, add a Form_Closing event. Look for the Closing event and double-click it.
  7. In the ContactDetails.cs source file, select all of the text by pressing CTRL+A, and then replace all of the code with the following code.
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Text;
    using System.Windows.Forms;
    using System.Runtime.InteropServices;
    using PocketOutlook;
    
    namespace UsingPOOM
    {
        public partial class ContactDetails : Form
        {
            private ContactItem thisContact;
            private bool isDirty;
            private bool newEntry;
    
            public ContactDetails(ContactItem contact, bool newEntryRequested)
            {
                InitializeComponent();
                thisContact = contact;
                isDirty = false;
                newEntry = newEntryRequested;
            }
    
            private void ContactDetails_Load(object sender, EventArgs e)
            {
                if (thisContact != null && !newEntry)
                {
                    tbName.Text = thisContact.FirstName + " " +
                        thisContact.LastName;
                    tbCompany.Text = thisContact.CompanyName;
                    tbPhone.Text = thisContact.BusinessTelephoneNumber;
                    tbEmail.Text = thisContact.Email1Address;
                    this.Text = "ContactDetails";
                    tbName.ReadOnly = true;
                }
                else if (newEntry)
                {
                    this.Text = "Add new Contact";
                    tbName.ReadOnly = false;
                }
            }
    
            private void tbName_TextChanged(object sender, EventArgs e)
            {
                isDirty = true;
            }
    
            private void tbCompany_TextChanged(object sender, EventArgs e)
            {
                isDirty = true;
            }
    
            private void tbPhone_TextChanged(object sender, EventArgs e)
            {
                isDirty = true;
            }
    
            private void tbEmail_TextChanged(object sender, EventArgs e)
            {
                isDirty = true;
            }
    
            private void ContactDetails_Closing(object sender, CancelEventArgs e)
            {
                if (isDirty)
                {
                    // The detailed information is changed.
                    // Update it in the contact list.
                    if (newEntry)
                    {
                        string[] nameParts;
                        nameParts = tbName.Text.Split(' ');
                        if (nameParts[0].Length == 0)
                        {
                            MessageBox.Show("Name field must be filled");
                            e.Cancel = true;
                        }
                        else
                        {
                            thisContact.FirstName = nameParts[0];
                            if (nameParts.Length == 2)
                            {
                                thisContact.LastName = nameParts[1];
                            }
                            else if (nameParts.Length > 2)
                            {
                                // Assuming that a middle name was
                                // entered as well,
                                // if more data was entered it will be
                                // ignored!
                                thisContact.MiddleName = nameParts[1];
                                thisContact.LastName = nameParts[2];
                            }
                        }
                    }
                    thisContact.CompanyName = tbCompany.Text;
                    thisContact.BusinessTelephoneNumber = tbPhone.Text;
                    thisContact.Email1Address = tbEmail.Text;
                    thisContact.Save();
                }
            }
        }
    }
    
    

    The code you have just added shows some detailed information for a selected Pocket Outlook contact. Most of the code consists of overhead to get a well-functioning user interface. The contact is passed in the constructor of the form, and the information is displayed on the form during execution of the ContactDetails_Load event. Whenever the user is changing some text in one of the text boxes, the isDirty flag is set to true. When the form is closed again, the modified information in the text boxes is stored to the contact database of Pocket Outlook.

    Of course, this application is very simple. It automatically stores modified data without asking the user whether modifications need to be stored. Rather than creating a fancy user interface and providing a large amount of code for that, this exercise concentrates on using POOM. The ContactDetails dialog is also reused to enter new contact information. For that purpose, the constructor also contains a Boolean variable newEntry. The biggest difference between updating and inserting a new contact can be seen in the ContactDetails_Closing event handler because, in the case of a new contact, a valid name must be entered. In the case of updating details, the name cannot be changed. Take some time studying the code in the ContactDetails.cs file, and especially note how data is stored in the Pocket Outlook contact database.

    The next thing you need to do is make a modification to the Form1.cs file so it displays the ContactDetails dialog when the Get Contact Details button is clicked. Prior to displaying the ContactDetails dialog, the currently selected contact in the list box is retrieved from the contact database and passed to the constructor of the ContactDetails dialog.

  8. Locate the btnDetails_Click event handler in the Form1.cs file, and then add the following code to it.
    Folder contactsFolder = 
        outlookApp.GetDefaultFolder(OlDefaultFolders.olFolderContacts);
    PocketOutlook.Items contacts = (PocketOutlook.Items)contactsFolder.Items;
    
    if (listBox1.SelectedIndex == -1)
        listBox1.SelectedIndex = 0;
    
    ContactDetails cd = new ContactDetails(
        (ContactItem) contacts.Item(listBox1.SelectedIndex+1), false);
    cd.ShowDialog();
    
    

    You have now finished adding functionality to display and modifying contact details. The next thing you will do is add code to the event handler for the Add new Contact button that, as you might remember, shares the ContactDetails dialog.

  9. Locate the btnNewContact_Click event handler in the Form1.cs file, and then add the following code to it.
    Folder contactsFolder = 
        outlookApp.GetDefaultFolder(OlDefaultFolders.olFolderContacts);
    PocketOutlook.Items contacts =  (PocketOutlook.Items)contactsFolder.Items;
    ContactItem contact = (ContactItem)contacts.Add();
    
    ContactDetails cd = new ContactDetails(contact, true);
    cd.ShowDialog();
    
    ShowContacts();
    
    

    The code for the btnNewContact_Click event handler and the code for the btnDetails_Click event handler are almost identical, with the exception of the way the constructor of the ContactDetails dialog is called and an additional update of the list box in case a new contact has been added.

    Next, you need to add some functionality to delete contact entries from the contact list. Again, the user interface is kept very simple. For instance, no confirmation is asked when you decide to delete a contact.

  10. Locate the btnDelContact_Click event handler in the Form1.cs file, and then add the following code to it.
    Folder contactsFolder = 
        outlookApp.GetDefaultFolder(OlDefaultFolders.olFolderContacts);
    PocketOutlook.Items contacts = (PocketOutlook.Items)contactsFolder.Items;
    
    if (listBox1.SelectedIndex == -1)
        listBox1.SelectedIndex = 0;
    
    ContactItem ci = (ContactItem)contacts.Item(listBox1.SelectedIndex + 1);
    ci.Delete();
    ShowContacts();
    
    

    Like updating and adding entries to the contact list, deleting entries from them is very straightforward when you are using POOM. It is simply a matter of selecting the correct entry in the PocketOutlook.Items list and calling its Delete method.

    The last thing to do before testing the application is add functionality to be able to enter appointments for a contact that you selected on the contact list.

  11. In the form designer, open the file AddAppt.cs.
    Note   The AddAppt.cs form already contains all of the user interface controls you will need, but the form does not yet contain any functionality.
  12. In AddAppt.cs [Design], click somewhere on the form outside the controls, and then in the Properties pane, click the Events button on the toolbar.
  13. Look for the Load event, and then double-click it.
  14. In the form designer, add a Form_Closing event. Look for the Closing event and double-click it.
  15. In the AddAppt.cs source file, select all of the text by pressing CTRL+A, and then replace all of the code with the following code.
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Text;
    using System.Windows.Forms;
    using System.Runtime.InteropServices;
    using PocketOutlook;
    
    namespace UsingPOOM
    {
        public partial class AddAppt : Form
        {
            private ContactItem thisContact;
            private AppointmentItem thisAppt;
    
            public AddAppt(ContactItem contact, AppointmentItem appt)
            {
                InitializeComponent();
                thisContact = contact;
                thisAppt = appt;
            }
    
            private void AddAppt_Load(object sender, EventArgs e)
            {
                tbName.Text = thisContact.FirstName + " " + thisContact.LastName;
                dtpDate.Value = DateTime.Now;
            }
    
            private void AddAppt_Closing(object sender, CancelEventArgs e)
            {
                if (tbSubject.Text.Length == 0)
                {
                    MessageBox.Show("You have to add a valid subject");
                    e.Cancel = true;
                }
                else
                {
                    thisAppt.Subject = tbName.Text + " - " + tbSubject.Text;
                    thisAppt.Start = dtpDate.Value;
                    thisAppt.Save();
                }
            }
        }
    }
    
    

    The code you have just added takes a name from the contact list and adds a new appointment for that particular contact. Adding contacts or adding appointments is more or less the same action. This time, to add a new appointment, you are collecting the appointment details and storing the appointment in the Pocket Outlook database by using the Add method. Just like the contacts, you have to be sure that you are using the correct folder where all appointments are stored. That is something you will set up in the event handler of the New Appointment button.

    The last modification that you need to make to the Form1.cs file is to display the AddAppts dialog when the New Appointment button is clicked. Prior to displaying the AddAppts dialog, the currently selected contact in the list box is retrieved from the contact database and passed to the constructor of the AddAppts dialog. A new, empty appointment is also passed to the dialog.

  16. Locate the btnNewAppt_Click event handler in the Form1.cs file, and then add the following code to it.
    Folder contactsFolder = 
        outlookApp.GetDefaultFolder(OlDefaultFolders.olFolderContacts);
    PocketOutlook.Items contacts =  (PocketOutlook.Items)contactsFolder.Items;
    
    Folder apptsFolder = outlookApp.GetDefaultFolder(OlDefaultFolders.olFolderCalendar);
    PocketOutlook.Items appts = (PocketOutlook.Items)apptsFolder.Items;
    AppointmentItem appt = (AppointmentItem)appts.Add();
    
    if (listBox1.SelectedIndex == -1)
        listBox1.SelectedIndex = 0;
    AddAppt aa = 
        new AddAppt((ContactItem)contacts.Item(listBox1.SelectedIndex + 1),
            appt);
    
    aa.ShowDialog();
    
    

    The only action that remains is for you to test the application. If you want to verify that the information entered in this application is also available in Pocket Outlook, you can simply change to either Contacts or Calendar and compare the information shown in those applications to the information that you entered in the UsingPOOM application.

  17. In Visual Studio, press F5 or select Debug | Start Debugging to start the application in debugging mode.
  18. Verify the correct operation of the application by testing all options, and regularly compare the results with Contacts and Calendar. You should feel free to enter, modify, and delete contacts as well as enter new appointments, as shown in Figure 20.

    Figure 20. Entering a new appointment

  19. When you are finished, close the application by clicking the ok button on the upper-right corner of the form.

Exercise 3: Accessing Pocket Outlook by Using Windows Mobile 5.0 Managed APIs

The .NET Compact Framework 2.0 contains great functionality to make interoperability with native code easier and more complete. In the previous exercises, you have seen that it is relatively easy to use COM components from inside a managed application. Using Windows Mobile 5.0 devices, it will even be easier to access some native components by means of managed APIs that will ship as part of the SDKs for those devices. Particularly, using the Telephony API and Pocket Outlook API will be very easy.

In this exercise, you will create a managed application for a Windows Mobile 5.0 Pocket PC that makes use of Pocket Outlook, just as you did in the previous exercise. There is one important difference, however. This time, you will make use of the Windows Mobile 5.0 Managed APIs, so there is no need to interoperate with COM components yourself. To compare the amount of code that you have to provide yourself, you will create an application with the same functionality as that in Exercise 2.

To open an existing solution and add functionality to it

  1. If it is not already running, open Visual Studio 2005.
  2. In Visual Studio 2005, click File | Open | Project/Solution.
  3. In the Open Project dialog box, browse to C:\Program Files\Windows Mobile Developer Samples\HOLs\MEDC06_HOL301\HOL301Exercise3.
  4. Select the HOL301Exercise3.sln file, and then click Open. The solution opens in Visual Studio 2005.

    The entire user interface is already created for you to save some time. In this exercise, you will add functionality to the application to access Pocket Outlook functionality, making use of the Windows Mobile 5.0 managed APIs.

  5. In the form designer, double-click each button on Form1 to add Click event handlers.
    Note   You have to switch back and forth between the Code view and the form designer to add click event handlers for all of the buttons.

In Windows Mobile 5.0–based devices, a lot of the device functionality is exposed by managed APIs. You can simply add a reference to the managed API that you need and start using it. All components starting with Microsoft.WindowsMobile contain managed wrappers around particular functionality.

To make Pocket Outlook work with your application

  1. In Solution Explorer under project ManagedPOOM, right-click References, and then click Add Reference.
  2. In the Add Reference dialog box, click the .NET tab, select Microsoft.WindowsMobile.PocketOutlook, and then click OK to add the reference to your project, as shown in Figure 21.

    Click here for larger image

    Figure 21. Add Reference dialog box. Click the thumbnail for a larger image.

    To be able to use Pocket Outlook inside your managed application, you need to add a namespace. You also need to create an instance to the Pocket Outlook application and log on to it by means of instantiating an OutlookSession object. Because you are going to use Pocket Outlook all through your application, OutlookSession will be available in an instance variable.

  3. Create an alias for the "Microsoft.WindowsMobile.PocketOutlook" namespace by adding the following statement immediately under the other using statements at the beginning of the Form1.cs file (this is the file into which all other code will be added as well).
    using Microsoft.WindowsMobile.PocketOutlook;
    
    
    Note   Because the "Microsoft.WindowsMobile.PocketOutlook" namespace contains true managed interfaces to Pocket Outlook, there is no need to set up COM Interop as you had to do in Exercise 2.
  4. Add the following instance variable to the Form1 class.
    private OutlookSession oSession;
    
    
  5. Open Form1.cs [Design] in Visual Studio 2005, and then click somewhere on the form outside the controls. In the Properties pane, click the Events button on the toolbar.
  6. Look for the Load event, and then double-click it. You now have created a Form1_Load event handler.
  7. In the Form1_Load event handler, add the following code.
    oSession = new OutlookSession();
    ShowContacts();
    
    
  8. In Form1.cs [Design] again, click somewhere on the form outside the controls. In the Properties pane, click the Events button on the toolbar.
  9. Look for the Closing event, and then double-click it. You now have created a Form1_Closing event handler.
  10. In the Form1_Closing event handler, add the following code.
    oSession.Dispose();
    
    
  11. Add a new method called ShowContacts to the Form1.cs file with the following code.
    private void ShowContacts()
    {
        // Fill the list box with contact information from Pocket     // Outlook
        ContactFolder cFolder = oSession.Contacts;
    
        listBox1.BeginUpdate();
        listBox1.Items.Clear();
    
        foreach (Contact contact in cFolder.Items)
        {
            string name = contact.FirstName + " " + contact.LastName;
            listBox1.Items.Add(name);
        }
    
        listBox1.EndUpdate();
    }
    
    

    If you compare the code for ShowContacts with ShowContacts in the previous exercise, you will see that it is extremely simple to access the contact database with Windows Mobile 5.0–based devices in combination with managed code. This is a great time to have a first test run of the application.

  12. On the Device toolbar, verify that the Windows Mobile 5.0 Pocket PC Emulator is selected as the target device.
  13. On the Device toolbar, click the Connect to Device button to set up a connection to the emulator.

    You will see the Windows Mobile 5.0 Pocket PC emulator starting when it has not been started already. When a connection with Visual Studio 2005 is established, a confirmation message appears in the connecting dialog; click Close to dismiss this dialog. To test your application, you first have to add one or two contacts in the contact database. If there are already contacts in the contact database, you can omit the following two steps.

  14. Be sure the Windows Mobile 5.0 Pocket PC emulator is visible.
  15. On the emulator, click Start | Contacts.
  16. Add a few new contacts (entering only names for contacts is sufficient).

    Now you are ready to deploy and run your application on the Windows Mobile 5.0 Pocket PC emulator.

  17. In Visual Studio 2005, press F5 or select Debug | Start Debugging to start the application in debugging mode.
  18. In the Deploy ManagedPoom dialog box, be sure that the Windows Mobile 5.0 Pocket PC Emulator is selected, and then click the Deploy button.

    After a while, you will see your application running inside the emulator. Immediately when the main form of the application is shown, you will see the contacts that you just entered in the contact database appear in the list box of your application. Those contacts are, of course, retrieved from the Outlook contact database.

  19. After verifying that the contacts are visible in the list box, you can close the application again by clicking the ok button on the upper-right side of the form.

To extend the application's functionality

  1. In the form designer, open the ContactDetails.cs file.
    Note   The ContactDetails.cs form already contains all of the user interface controls that you need, but the form does not yet contain any functionality.
  2. Add TextChanged event handlers for each of the text boxes. To add TextChanged event handlers, click the text box, find the TextChanged event in the Properties pane (you have to click the Events button to see all available events), and then double-click it.
  3. In ContactDetails.cs [Design], click somewhere on the form outside the controls. In the Properties pane, click the Events button on the toolbar.
  4. Look for the Load event, and then double-click it.
  5. In the form designer, add a Form_Closing event. Look for the Closing event, and then double-click it.
  6. In the ContactDetails.cs source file, select all of the text by typing CTRL+A, and then replace all of the code with the following code.
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Text;
    using System.Windows.Forms;
    using Microsoft.WindowsMobile.PocketOutlook;
    
    namespace ManagedPOOM
    {
        public partial class ContactDetails : Form
        {
            private Contact thisContact;
            private bool isDirty;
            private bool newEntry;
    
            public ContactDetails(Contact contact, bool newEntryRequested)
            {
                InitializeComponent();
                thisContact = contact;
                isDirty = false;
                newEntry = newEntryRequested;
            }
    
            private void ContactDetails_Load(object sender, EventArgs e)
            {
                if (thisContact != null && !newEntry)
                {
                    tbName.Text = thisContact.FirstName + " " +
                        thisContact.LastName;
                    tbCompany.Text = thisContact.CompanyName;
                    tbPhone.Text = thisContact.BusinessTelephoneNumber;
                    tbEmail.Text = thisContact.Email1Address;
                    this.Text = "ContactDetails";
                    tbName.ReadOnly = true;
                }
                else if (newEntry)
                {
                    this.Text = "Add new Contact";
                    tbName.ReadOnly = false;
                }
            }
    
            private void tbName_TextChanged(object sender, EventArgs e)
            {
                isDirty = true;
            }
    
            private void tbCompany_TextChanged(object sender, EventArgs e)
            {
                isDirty = true;
            }
    
            private void tbPhone_TextChanged(object sender, EventArgs e)
            {
                isDirty = true;
            }
    
            private void tbEmail_TextChanged(object sender, EventArgs e)
            {
                isDirty = true;
            }
    
            private void ContactDetails_Closing(object sender, CancelEventArgs e)
            {
                if (isDirty)
                {
                    // The detailed information is changed.
                    // Update it in the contact list.
                    if (newEntry)
                    {
                        string[] nameParts;
                        nameParts = tbName.Text.Split(' ');
                        if (nameParts[0].Length == 0)
                        {
                            MessageBox.Show("Name field must be filled");
                            e.Cancel = true;
                        }
                        else
                        {
                            thisContact.FirstName = nameParts[0];
                            if (nameParts.Length == 2)
                            {
                                thisContact.LastName = nameParts[1];
                            }
                            else if (nameParts.Length > 2)
                            {
                                // Assuming that a middle name was
                                // entered as well,
                                // if more data was entered it will be
                                // ignored!
                                thisContact.MiddleName = nameParts[1];
                                thisContact.LastName = nameParts[2];
                            }
                        }
                    }
                    thisContact.CompanyName = tbCompany.Text;
                    thisContact.BusinessTelephoneNumber = tbPhone.Text;
                    thisContact.Email1Address = tbEmail.Text;
                    thisContact.Update();
                }
            }
        }
    }
    
    

    Because this code mainly deals with controlling the user interface, the majority of it is identical to the code that you had to add for the ContactDetails form in Exercise 2. The biggest difference is that you now use a Contact object to refer to contact information, instead of a ContactItem object. Another difference is that you use an Update method to store changes to a contact instead of a Save method. For an explanation of the code, you can reread the description of the ContactDetails form in Exercise 2.

    The next thing you need to do is modify the Form1.cs file to be able to display the ContactDetails dialog when the Get Contact Details button is clicked. Prior to displaying the ContactDetails dialog, the currently selected contact in the list box is retrieved from the contact database and passed to the constructor of the ContactDetails dialog.

  7. Locate the btnDetails_Click event handler in the Form1.cs file, and then add the following code to it.
    ContactFolder cFolder = oSession.Contacts;
    if (listBox1.SelectedIndex == -1)
        listBox1.SelectedIndex = 0;
    ContactDetails cd = new ContactDetails(cFolder.Items[listBox1.SelectedIndex],
       false);
    cd.ShowDialog();
    
    

    Comparing the code of the btnDetails_Click event handler with the same event handler in Exercise 2 makes it clear that using the Windows Mobile 5.0 managed APIs is very straightforward. You have now finished with adding functionality to display and modify contact details. Next, you will add code to the event handler for the Add new Contact button that, as you might remember from the previous exercise, shares the ContactDetails dialog.

  8. Locate the btnNewContact_Click event handler in the Form1.cs file, and then add the following code to it.
    ContactFolder cFolder = oSession.Contacts;
    ContactDetails cd = new ContactDetails(cFolder.Items.AddNew(),true);
    cd.ShowDialog();
    ShowContacts();
    
    

    As you can see, the code for the btnNewContact_Click event handler and the code for the btnDetails_Click event handler are almost identical, with the exception of the way the constructor of the ContactDetails dialog is called and an additional update of the list box in case a new contact has been added.

    Next, you will add some functionality to delete contact entries from the contact list. Again, the user interface is kept very simple; for instance, no confirmation is asked when you decide to delete a contact.

  9. Locate the btnDelContact_Click event handler in the Form1.cs file, and then add the following code to it.
    ContactFolder cFolder = oSession.Contacts;
    if (listBox1.SelectedIndex == -1)
        listBox1.SelectedIndex = 0;
    cFolder.Items[listBox1.SelectedIndex].Delete();
    ShowContacts();
    
    

    Like updating and adding entries to the contact list, deleting entries from them is very straightforward. It is simply a matter of selecting the correct entry in the ContactFolder Items collection list and calling its Delete method.

    The last thing to do before testing the application is add functionality to be able to enter appointments for a contact that you selected on the contact list.

  10. In the form designer, open the AddAppt.cs file.
    Note   The AddAppt.cs form already contains all of the user interface controls that you need, but the form does not yet contain any functionality.
  11. In AddAppt.cs [Design], click somewhere on the form outside the controls. In the Properties pane, click the Events button on the toolbar.
  12. Look for the Load event, and then double-click it.
  13. In the form designer, add a Form_Closing event. Look for the Closing event, and then double-click it.
  14. In the AddAppt.cs source file, select all of the text by pressing CTRL+A, and then replace all of the code with the following code.
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Text;
    using System.Windows.Forms;
    using Microsoft.WindowsMobile.PocketOutlook;
    
    namespace ManagedPOOM
    {
        public partial class AddAppt : Form
        {
            private Contact thisContact;
            private Appointment thisAppt;
    
            public AddAppt(Contact contact, Appointment appt)
            {
                InitializeComponent();
                thisContact = contact;
                thisAppt = appt;
            }
    
            private void AddAppt_Load(object sender, EventArgs e)
            {
                tbName.Text = thisContact.FirstName + " " + thisContact.LastName;
                dtpDate.Value = DateTime.Now;
            }
    
            private void AddAppt_Closing(object sender, CancelEventArgs e)
            {
                if (tbSubject.Text.Length == 0)
                {
                    MessageBox.Show("You have to add a valid subject");
                    e.Cancel = true;
                }
                else
                {
                    thisAppt.Subject = tbName.Text + " - " + tbSubject.Text;
                    thisAppt.Start = dtpDate.Value;
                    thisAppt.Update();
                }
            }
        }
    }
    
    

    As with the ContactDetails dialog, the majority of the code that you have just added deals with the user interface. However, if you compare the code of the ContactDetails.cs source file with the code of AddAppt.cs source file, you can see that adding an appointment or adding a new contact are very similar actions. To be able to use the functionality that you just added, you must now implement the event handler of the New Appointment button.

    You need to make one last modification to the Form1.cs file to be able to display the AddAppts dialog when the New Appointment button is clicked. Prior to displaying the AddAppts dialog, the currently selected contact in the list box is retrieved from the contact database and passed to the constructor of the AddAppts dialog. A new, empty appointment is also passed to the dialog.

  15. Locate the btnNewAppt_Click event handler in the Form1.cs file, and then add the following code to it.
    ContactFolder cFolder = oSession.Contacts;
    AppointmentFolder aFolder = oSession.Appointments;
    if (listBox1.SelectedIndex == -1)
        listBox1.SelectedIndex = 0;
    AddAppt aa = new AddAppt(cFolder.Items[listBox1.SelectedIndex],
                             aFolder.Items.AddNew());
    aa.ShowDialog();
    
    

    The only action that remains is for you to test the application. If you want to verify that the information entered in this application is also available in Pocket Outlook, you can simply change to either Contacts or Calendar and then compare the information shown in those applications to the information that you entered in the ManagedPOOM application.

  16. In Visual Studio 2005, press F5 or select Debug | Start Debugging to start the application in debugging mode.
  17. Verify the correct operation of the application by testing all of the options, and regularly compare the results with Contacts and Calendar. You should feel free to enter, modify, and delete contacts as well as enter new appointments.
  18. When you are finished, close the application by clicking the ok button on the upper-right corner of the form.

Summary

In this lab, you performed the following exercises:

  • Creating and using a COM object by using Visual Studio 2005
  • Accessing Pocket Outlook inside a managed application
  • Accessing Pocket Outlook by using Windows Mobile 5.0 managed APIs

In this lab, you created a number of applications to explore the COM interoperability features of the .NET Compact Framework 2.0. You learned how to use a COM component that you wrote from scratch by using ATL inside a managed application. You also learned how to use existing COM components inside a managed application, by using the Pocket Outlook Object Model. Finally, you experienced that even with great COM support in the .NET Compact Framework version 2.0, using existing applications with a COM interface on a next-generation Windows Mobile–based device is even easier by making use of managed APIs that expose functionality of those applications and components.

Appendix A. Terminating an Application That Is Running on a Device or Emulator

This appendix describes how to terminate an application that is running on a device or emulator. This is useful for cases where an application has been started without having the debugger attached and the application needs to be terminated so a new copy of the application can be deployed. You will terminate the application by using the Remote Process Viewer remote tool in Visual Studio.

Before you can terminate a process, you need to know the name of the executable file. In most cases, this is the same name as the Visual Studio project. If you are uncertain about the name of the executable file, you can find it in the project's properties.

To terminate an application that is running on a device or emulator by using the Remote Process Viewer remote tool

  1. In Visual Studio, click Project | xxx Properties, where xxx represents the name of the current project.
  2. In the Project Properties dialog box, note the value in the Assembly Name box. This is the name that the executable file will be running on the device or emulator.
  3. Close the Properties dialog box.

    Now, you can terminate the process.

  4. On the desktop computer, click Start | Microsoft Visual Studio 2005 | Visual Studio Remote Tools | Remote Process Viewer.
  5. When prompted by the Select a Windows CE Device dialog box, select the emulator or device where the application is running, as shown in Figure 22, and then click OK.

    Figure 22. Select a Windows CE Device dialog box

  6. After the connection to the emulator or device completes, select the application that you want to terminate in the top pane of the Remote Process Viewer, as shown in Figure 23.

    Click here for larger image

    Figure 23. Selecting the application to terminate. Click the thumbnail for a larger image.

    You may need to widen the Process column (the leftmost column) to fully view the process names.

  7. In Windows CE Remote Process Viewer, click File | Terminate Process to terminate the process.
    Note   Be certain that the correct process is selected before you click Terminate Process. Terminating the incorrect process may render the device or emulator unusable, requiring it to be reset before you can use it again.
  8. Verify that the process is terminated by selecting Target | Refresh. Scroll to the top pane of Windows CE Remote Process Viewer again. If the application name still appears, the process was not terminated, and you need to repeat these steps.
    Note   Most processes terminate in one try; however, depending on the state of the application, terminating a process occasionally takes two attempts.

Appendix B: Setting Up Your Computer

The following lab files are required to set up your computer to run this HOL:

  • Pre-existing Visual Studio 2005 project, code, and data files.

    To install these files to the correct path, download and run the following installation program: MEDC06_HOL301.msi.

    Note   If you used an emulator in a previous HOL, you should do a hard reset on the emulator before starting this HOL. (On the emulator, click File | Reset | Hard.)
    Note    If you receive an error during deployment that indicates that the process or file is in use, this means that the program is still running on the emulator and must be closed before a new copy can be deployed and run. This error may appear anytime in the lab that you deploy the emulator. See Appendix A in this HOL for instructions about exiting a running application.
Show:
© 2014 Microsoft