Controlling EWF by Using the EWF APIs

 

Sean D. Liming
A7 Engineering

May 2004

Applies to:
     Microsoft® Windows® XP Embedded
     Microsoft Visual Studio® .NET 2003

Summary: Windows XP Embedded includes Enhanced Write Filter (EWF), which provides a means for protecting a volume from disk writes. This article provides several examples that demonstrate how to create applications by using the set of EWF application programming interfaces (APIs) through Visual Studio .NET 2003.

Contents

Introduction
EWF High-Level Description
Setup and Working with the Examples
Conclusion
References

Introduction

The Write Filter component in Microsoft® Windows NT® Embedded provides basic support to protect a hard disk from read and write access. It also allows Windows NT to start from CD-ROM and read-only media. However, the read-only feature of the Write Filter component lacks the flexibility that you need to make changes or updates to the operating system image. You cannot turn off the Write Filter component or perform incremental updates to images. Improvements and enhancements to the Write Filter component became a key focus during the development of Microsoft Windows® XP Embedded.

The Enhanced Write Filter (EWF) component in Windows XP Embedded features the ability to enable or disable read-only support, a choice of overlay (random access memory [RAM] or disk), flexible setup to protect specific partitions, and the EWFMGR tool that enables users to take control of EWF. There was still one more feature that the original equipment manufacturers (OEMs) wanted in the EWF component: the ability to build applications that control EWF programmatically.

The Windows XP Embedded team responded to the feedback by creating a set of EWF APIs. The APIs are delivered in a quick fix engineering (QFE) update (Q818822, May 2003) so that developers can update their databases with the latest fixes and receive the header and library files that are required to build applications through the EWF APIs. The EWF APIs enable applications to query and modify EWF configuration settings for protected volumes. Typical usage scenarios for these functions include:

  • Disabling or enabling EWF for a protected volume.
  • Restoring or discarding an overlay level.
  • Creating a checkpoint by adding an overlay level.
  • Committing the current overlay.
  • Persisting data through a restart.

This article provides several examples that demonstrate how to create applications by using the EWF APIs through Microsoft Visual Studio® .NET 2003.

EWF High-Level Description

You can use the EWF component to protect a volume from disk writes. EWF allows the operating system to start from read-only media, such as CD-ROMs, write-protected hard disks, or flash media, and all writes to the EWF-protected volume are redirected to an overlay. These writes are cached in the overlay and made available as part of the volume, giving the appearance that the volume is writeable. The overlay may exist on a disk, in RAM, or in the registry. The data that is stored in the overlay can be committed to the protected volume if the volume is writeable.

Applications can therefore read data from the protected volume. If data is changed and written back, the information is stored in the overlay and not on the original disk. Any subsequent reads of the data will occur from the overlay.

RAM overlays can lose data when the system is turned off or restarted, but using either a management tool (EWFMGR) or an application that uses the EWF APIs' changes can save to the protected volume. For example, all configurations that are built to support Transmission Control Protocol/Internet Protocol (TCP/IP) and networking are built with a DHCP client. The user can set up a static TCP/IP address, and then use EWFMGR or another application that uses the EWF API set to commit changes to the protected volume.

Setup and Working with the Examples

To re-create the examples that are in this article, you need to download the "May 2003, Programmatically control EWF APIs (Q818822)" QFE from the Important Updates Web page. The Q818822.exe file is a self-extracting ZIP file. Extract the files to a folder like c:\xpeewf. The ZIP file contains the files that are listed in the following table.

Table 1. QFE818822 Contents

File Description
Ewfapi.chm Help file for the EWF APIs
Ewfapi.h Header file to be included in applications
Ewfapi.lib Library file to be linked into applications
Ewfapi_relnotes.rtf EWF API release notes
Q818822_XPE_SP2_X86_ENU.exe QFE update for the Windows XP Embedded database; the update contains a component that is required for Ewfapi.dll, which is required for use with any application that implements the EWF APIs

On the computer where the Windows XP Embedded database is stored, run Q818822_XPE_SP2_X86_ENU.exe to update the database with the new component—EWF API. Now you are ready to start creating applications by using Ewfapi.h and Ewfapi.lib.

The following three examples demonstrate how you can implement the EWF APIs in a console application and a Microsoft Foundation Classes (MFC) application. Examples 1 and 2 are console applications that can work for most situations. They are really smaller versions of the EWFMGR tool that is included with Windows XP Embedded. Console applications are ideal when performing remote administration on a headless system.

Example 1 (Ewfcmd.exe) provides the simple control of enable, disable, and commit. You can further modify Ewfcmd.exe to add restart or shutdown capability. Example 2 (Ewfstatus.exe) provides basic status on all EWF-protected volumes in a system. You can further modify Ewfstatus.exe to provide information about the space that is available in the overlay and other overlay details.

Example 3 (Ewfshell.exe) is a Microsoft Visual C++® static MFC application that you can use as a shell in a Windows XP Embedded image. Ewfshell.exe combines the EWF APIs and the XPEPM APIs to support a specific Windows XP Embedded configuration. Ewfshell.exe demonstrates one way that you can use the EWF APIs in a Windows-based application.

Example 1: Ewfcmd.exe

Example 1 shows a simple command-prompt application that calls three of the EWF APIs: EfwMgrEnable, EwfMgrDisable, and EwfMgrCommit. The EWFMGR tool will accept two command-prompt parameters: the drive and the EWF operation parameter. Use the command as follows: Ewfcmddriveoperation_parameter. The EWF operation parameter is -E (enable EWF), -D (disable EWF), or -C (commit change from overlay to protected volume).

If either parameter is missing, Help will be displayed. Because parameters are strings, the dash can be ignored by using argv[2][1] to act on the specific EWF operation.

To create the Ewfcmd application:

  1. Open Visual Studio .NET 2003.

  2. On the File menu, click New Project.

  3. In the New Project dialog box, under Project Types, expand Visual C++ Projects, and then click Win32.

  4. Under Templates, click Win32 Console Project.

  5. In the Name box, type ewfcmd as shown in Figure 1.

    Figure 1. Opening Win32 Console Project

  6. Click OK.

  7. In the Win32 Application Wizard, click Finish.

  8. Copy Ewfapi.h to the directory of the project so that it exists in the same directory as the other project files.

  9. In Solutions Explorer, right-click Source Files, and then click Add Existing Item.

  10. The Open Add Existing Item dialog box opens to the project directory. Select the ewfapi.h file, and then click Open. Figure 2 shows the result.

    Figure 2. Adding ewfapi.h to the project

  11. Make sure that ewfcmd.cpp has focus. You need to add Ewfapi.lib to the project. On the Project menu, click ewfcmd Properties.

  12. In the ewfcmd Property Pages dialog box, you have custom control to build the application. In the Configuration list, select All Configurations.

  13. In the Configuration Properties tree, expand Linker, and then select Input.

  14. Select Additional Dependencies, and then click the box with three dots.

  15. Type the path to Ewfapi.lib, as shown in Figure 3, and then click OK.

    Figure 3. Adding Ewfapi.lib to the project

  16. Click OK again to close the ewfcmd Property Pages dialog box.

  17. Enter the following code for the Ewfcmd.cpp file.

    //ewfcmd.cpp: Defines the entry point for the console application.
    //
    //Copyright (c) 2003 A7 Engineering
    //Code is provided as is without any warranty
    //
    //Description: Command-prompt application that demonstrates how to
    //            implement the EWF APIs for three simple
    //            commands: Enable EWF, Disable EWF, and Commit
    //            changes to a protect volume.
    //            Each command requires a manual restart for
    //            the change to take effect.
    //
    //            Shutdown and restart can happen in three ways:
    //            1. By using the FBA.exe application
    //               c:\windows\fba>fba -shutdown
    //               c:\windows\fba>fba -reboot
    //            2. By using the ExitWindowsEx API command
    //            3. By using the XPEPM APIs that are provided
    //            on Windows XP Embedded CD1
    //
    //Note: For RAM overlays, pressing the system reset button will not
    //         commit changes to the protected volume. You must shut
    //         down or restart the system through one of the
    //         preceding methods.
    //
    //Note also: EWFCMD assumes only disk and RAM overlays.
    //         Make the modifications for the EWF RAM REG overlay.
    //
    //
    
    
    #include "stdafx.h"
    #include <stdio.h>
    #include <windows.h>
    #include "ewfapi.h"
    void DisplayHelp();
    
    int wmain(int argc, wchar_t* argv[])
    {
       HANDLE hDisk;
       WCHAR szDrive[20];
       DWORD dwStatus = ERROR_SUCCESS;
       BOOL bResult =FALSE;
    
       wprintf(L"\nEWFCMD - EWF API Example\n");
       wprintf(L"Copyright (c) 2003 A7 Engineering\n\n");
    
       //The IF statement holds the main body of the application.
       //The IF statement checks to make sure that command-prompt
       //arguments are correct. If the command-prompt arguments are
       //incorrect, display Help.
    
       if (   (argc == 3)
       &&   (L'-' == argv[2][0]))
       {
    
          //Open the handle to the volume and check whether the
          //volume is valid.
          //First step is to put the drive parameter in the correct
          //format:
          // \\.\c:swprintf(szDrive, L"\\\\.\\%s", argv[1]);
    
          //Next, open the handle and check for errors.
          hDisk = EwfMgrOpenProtected(szDrive);
          if (INVALID_HANDLE_VALUE == hDisk) 
          {
             wprintf(L"Invalid Handle. Please make sure that the
     drive exists\n");
             DisplayHelp();
             return 1;
          }
    
          //The switch statement is based on the second parameter to
          //carry out the action to perform on the volume handle.
          //Look at the second character of the second argument to
          //perform the specific EWF operation.
          switch (argv[2][1])
             {
    
             //E for Enable EWF
             case 'E':
                {
    
                   bResult = EwfMgrEnable(hDisk);
                   if (!bResult)
                   {
                      dwStatus = GetLastError();
                      wprintf(L"EwfMgrEnable failed LE = 
    %u\n",dwStatus);
                      EwfMgrClose(hDisk);
                      return 1;
                   }
    
                   wprintf(L"EWF Enabled - ");
                   wprintf(L"Reboot system for change to 
    take effect\n");
                   EwfMgrClose(hDisk);
                }
                break;
    
             //D for Disable EWF
             case 'D' :
                {
                   //For EWF RAM REG configurations, the
                   //second parameter (commit) must be
                   //TRUE. This will commit the EWF RAM REG
                   //disable state, which is required to
                   //disable the EWF RAM REG configuration.
    
                   bResult = EwfMgrDisable(hDisk,FALSE);
                   if (!bResult)
                   {
                      dwStatus = GetLastError();
                      wprintf(L"EwfMgrDisable failed LE = 
    %u\n",dwStatus);
                      EwfMgrClose(hDisk);
                      return 1;
                   }
    
                   wprintf(L"EWF Disabled - ");
                   wprintf(L"Reboot system for change to 
    take effect\n");
                   EwfMgrClose(hDisk);
                }
                break;
    
             //C for Commit changes to protected volume
             case 'C' :
                {
                   bResult = EwfMgrCommit(hDisk);
                   if (!bResult)
                   {
                      dwStatus = GetLastError();
                      wprintf(L"EwfMgrCommit failed LE = 
    %u\n",dwStatus);
                      EwfMgrClose(hDisk);
                      return 1;
                   }
    
                   wprintf(L"Changes commited - ");
                   wprintf(L"Reboot system for change to 
    take effect\n");
                   EwfMgrClose(hDisk);
                }
                break;
    
             default:
                DisplayHelp();
                return 1;
             }
       }
       else
       {
          //If the parameter conditions fail, display Help.
          DisplayHelp();
          return 1;
       }
    
       return 0;
    }
    
    void DisplayHelp()
    {
       wprintf(L"\nEWFCMD <Drive> <Option>\n");
       wprintf(L"-E Enable EWF\n");
       wprintf(L"-D Disable EWF\n");
       wprintf(L"-C Commit Changes to Protect Volume\n");
    }
    
    
    
  18. Build the application.

  19. Use Component Designer to create a component for the Ewfcmd.exe application. Expand Software, expand System, expand Management, and then place the new component in the Application category.

  20. Import the new component into the database.

  21. Create a Windows XP Embedded configuration by using Target Designer. Be sure that you include the following components:

    • EnableAutoLayout (for more information, see the El Torito topic in Windows XP Embedded Help)
    • EWF Manager Console Application (use this application to test against)
    • Enhanced Write Filter (EWF)
    • EWF API
    • EWF NTLD
    • Minlogon
    • Task Manager Shell
    • FAT file system
    • NTFS file system
  22. Include the component that was created for the application.

  23. Make sure that you have imported the PMQ information for the target platform.

  24. Make sure that your target has a hard disk that is divided into two partitions: one partitioned to use the FAT file system or the NTFS file system and the other left unpartitioned. The second partition must be 8 megabytes (MB) in size.

  25. Modify the Enhanced Write Filter settings so that EWF will protect the first partition on the target's hard disk drive. Use either RAM or Disk Overlay.

  26. Check dependencies, build the configuration, download to the target's first partition, and then start the Windows XP Embedded operating system image.

  27. When the Task Manager shell appears, click New Task, and then type CMD in the box.

  28. Click OK.

  29. In the Command Prompt window, use EWFMGR to make sure that EWF was set up properly during the First Boot Agent (FBA) processes.

  30. Test Ewfcmd.exe to enable and disable EWF. For example, to disable EWF, run ewfcmd c: -D for C:\windows\system32. You will have to restart the system each time that you run the application.

    EWFCMD - EWF API Example

    Copyright (c) 2003 A7 Engineering

Example 2: Ewfstatus.exe

Ewfstatus.exe lists the basic status and information for all of the EWF-protected volumes that are in the system. Several of the EWF API structures are used to hold and display the information for each volume. The EWF API combination of EwfMgrVolumeNameListIsEmpty and EwfMgrVolumeNameEntryPop is used to search through the stack of volumes in a system so that the status for each volume can be displayed.

To create the Ewfstatus application:

  1. Open Visual Studio .NET 2003.

  2. On the File menu, click New Project.

  3. In the New Project dialog box, under Project Types, expand Visual C++ Projects, and then click Win32.

  4. Under Templates, click Win32 Console Project.

  5. In the Name box, type EWFSTATUS as shown in Figure 4.

    Figure 4. Opening Win32 Console Project

  6. Click OK.

  7. In the Win32 Application Wizard, click Finish.

  8. Copy Ewfapi.h to the directory of the project so that it exists in the same directory as the other project files.

  9. In Solutions Explorer, right-click Source Files, and then click Add Existing Item.

  10. The Open Add Existing Item dialog box opens to the project directory. Select the ewfapi.h file, and then click Open. Figure 5 shows the result.

    Figure 5. Adding ewfapi.h to the project

  11. Make sure that Ewfstatus.cpp has focus. You need to add Ewfapi.lib to the project. On the Project menu, click ewfstatus Properties.

  12. In the ewfcmd Property Pages dialog box, you have custom control to build the application. In the Configuration list, select All Configurations.

  13. In the Configuration Properties tree, expand Linker, and then select Input.

  14. Select Additional Dependencies, and then click the box with three dots.

  15. Type the path to Ewfapi.lib, as shown in Figure 6, and then click OK.

    Figure 6. Adding Ewfapi.lib to the project

  16. Click OK again to close the ewfcmd Property Pages dialog box.

  17. Enter the following code for the Ewfcmd.cpp file.

    //Ewfstatus.cpp: Defines the entry point for the console
    //application.
    //
    //Copyright (c) 2003 A7 Engineering
    //Code is provided as is without any warranty
    //
    //Description: Command-prompt application that demonstrates how to
    //            implement the EWF APIs and
    //            structures. EWFSTATUS provides
    //            the information about the protected volumes:
    //            overlay type, current state of protection
    //            (enabled/disabled), and whether there are any
    //            pending startup commands (such as enable,
    //            disable, or commit). There are no command-
    //            prompt parameters for the application.
    //
    //EWF API functions that are used:
    //
    //         EwfMgrGetProtectedVolumeList
    //         EwfMgrVolumeNameListIsEmpty
    //         EwfMgrGetDriveLetterFromVolumeNam
    //         EwfMgrOpenProtected
    //         EwfMgrGetProtectedVolumeConfig
    //         EwfMgrClose
    //         EwfMgrVolumeNameListDelete
    //         EwfMgrVolumeNameEntryPop
    //
    //
    //EWF API structures that are used:
    //
    //         EWF_VOLUME_CONFIG
    //         EWF_VOLUME_NAME_ENTRY
    //         EWF_MAX_DEVICE_NAME_LENGTH
    //
    
    #include "stdafx.h"
    #include <stdio.h>
    #include <windows.h>
    #include "ewfapi.h"
    
    
    int wmain(int argc, wchar_t* argv[])
    {
       HANDLE hDisk = INVALID_HANDLE_VALUE;;
       DWORD dwStatus = ERROR_SUCCESS;
       BOOL bResult =FALSE;
       PEWF_VOLUME_CONFIG pVolConfig = NULL;
       PEWF_VOLUME_NAME_ENTRY pProVolList = NULL;
       WCHAR szVolumeName[EWF_MAX_DEVICE_NAME_LENGTH + 15] = {0};
       WCHAR chDrive = NULL;
    
    
       wprintf(L"\nEWFSTATUS - EWF API Example\n");
       wprintf(L"Copyright (c) 2003 A7 Engineering\n");
    
       wprintf(L"\n");
       wprintf(L"-------------------------------------------------------
    -\n");
       wprintf(L"-- Ewf protected volume configuration                   
    \n");
       wprintf(L"-------------------------------------------------------
    -\n\n");
    
       //Get a list of protected volume names, and check for any
       //errors.
       //If the list is not found, display an error and exit.
       pProVolList = EwfMgrGetProtectedVolumeList();
       if (!pProVolList) 
       {
          dwStatus = GetLastError();
          wprintf(L"EwfMgrGetProtectedVolumeList failed LE = 
    %u\n",dwStatus);
          return 1;
       }
    
       //Process and free each volume name that is in the list.
       //The while loop continues as long as the protected volume list
       //has not reached the end. The last command,
       //EwfMgrVolumeNameEntryPop, makes the pProVolList structure
       //point to the next volume that is in the list.
    
       while (!EwfMgrVolumeNameListIsEmpty(pProVolList))
       {
    
          //Get the drive letter that is assigned to this protected
          //volume name.
          //If there is an error, display the error and exit;
          //otherwise, display the drive letter.
          chDrive = EwfMgrGetDriveLetterFromVolumeName(pProVolList-
    >Name);
          if (chDrive == -1) 
          {
             dwStatus = GetLastError();
             wprintf(L"EwfMgrGetDriveLetterFromVolumeName failed 
    LE = %u\n",dwStatus);
             return 1;
          }
          wprintf(L"DRIVE            : %c\n",chDrive);
    
          //Next, open the handle and check for errors.
          //Using the Volume Name List, open a handle to
          //the current protected volume.
          hDisk = EwfMgrOpenProtected(pProVolList->Name);
          if (INVALID_HANDLE_VALUE == hDisk) 
          {
             wprintf(L"Invalid Handle.\n");
             return 1;
          }
    
          //Get the protected volume configuration by using the
    //handle.
          pVolConfig = EwfMgrGetProtectedVolumeConfig(hDisk);
          if (!pVolConfig)
          {
             dwStatus = GetLastError();
             wprintf(L"EwfMgrGetProtectedVolumeConfig failed LE = 
    %u\n",dwStatus);
             return 1;
          }
    
          //Now display the status for the protected volume.
          //Display the overlay type.
          switch (pVolConfig->Type)
          {
             case EWF_DISK:      wprintf(L"OVERLAY TYPE     : 
    EWF_DISK\n");    break;
             case EWF_RAM:       wprintf(L"OVERLAY TYPE     : 
    EWF_RAM\n");     break;
             case EWF_RAM_REG:   wprintf(L"OVERLAY TYPE     : 
    EWF_RAM_REG\n"); break;
             default:
             wprintf(L"ERROR: Unknown Ewf type\n"); 
             break;
          }
    
          //Display this protected volume's state.
          switch (pVolConfig->State)
          {
             case EWF_ENABLED:   wprintf(L"CURRENT STATE    : 
    EWF_ENABLED\n");  break;
             case EWF_DISABLED:  wprintf(L"CURRENT STATE    : 
    EWF_DISABLED\n"); break;
             default:
             wprintf(L"ERROR: Unknown Ewf state\n");
             break;
          }
    
          //Display this protected volume's startup command.
          switch (pVolConfig->BootCommand.Command)
          {
             case EWF_NO_CMD:    wprintf(L"BOOT CMD         : 
    EWF_NO_CMD    ");  break;
             case EWF_ENABLE:    wprintf(L"BOOT CMD         : 
    EWF_ENABLE    ");  break;
             case EWF_DISABLE:   wprintf(L"BOOT CMD         : 
    EWF_DISABLE   ");  break;
             case EWF_COMMIT:    wprintf(L"BOOT CMD         : 
    EWF_COMMIT    ");  break;
             case EWF_SET_LEVEL: wprintf(L"BOOT CMD         : 
    EWF_SET_LEVEL ");  break;
             default:
             wprintf(L"ERROR: Unknown Ewf command ");   
             break;
          }
    
          //Display the EWF command parameters.
          wprintf(
             L" Param1 = %u  Param2 = %u\n\n",
             pVolConfig->BootCommand.Param1,
             pVolConfig->BootCommand.Param2);
    
          wprintf(L"\n"); // New line for next volume
    
          //
          //
          //Now clean up the handles and structures for the next
          //volume.
          //
          //
    
          LocalFree(pVolConfig);
          pVolConfig = NULL;
    
          //Close the handle to this protected volume.
          if (!EwfMgrClose(hDisk))
          {
             dwStatus = GetLastError();
             wprintf(L"EwfMgrClose failed LE = %u\n",dwStatus);
             return 1;
          }
    
          //Reset the handle.
          hDisk = INVALID_HANDLE_VALUE;
    
          //Pop and free the head node of the protected volume list.
          //The next volume that is in the chain moves to the top
          //of the list.
          EwfMgrVolumeNameEntryPop(&pProVolList);
    
      }
    
    //The while loop has finished. Now clean up the handles and
    //structures.
    
      if (pProVolList) 
      {
        EwfMgrVolumeNameListDelete(pProVolList);
        pProVolList = NULL;
      }
    
      if (hDisk != INVALID_HANDLE_VALUE)
      {
        EwfMgrClose(hDisk);
      }
    
      if (pVolConfig)
      {
        LocalFree(pVolConfig);
      }
       return 0;
    }
    
  18. Build the application.

  19. Using Component Designer, create a component for the Ewfstatus.exe application. Expand Software, expand System, expand Management, and then place the new component in the Application category.

  20. Import the new component into the database.

  21. Create a Windows XP Embedded configuration by using Target Designer. Be sure that you include the following components:

    • EnableAutoLayout (for more information, see the El Torito topic in Windows XP Embedded Help )
    • EWF Manager Console Application (use this application to test against)
    • Enhanced Write Filter (EWF)
    • EWF API
    • EWF NTLD
    • Minlogon
    • Task Manager Shell
    • FAT file system
    • NTFS file system
  22. Include the component that was created for the application.

  23. Make sure that you have imported the PMQ information for the target platform.

  24. Make sure that your target has a hard disk that is divided into two partitions: one partitioned to use the FAT file system or the NTFS file system and the other left unpartitioned. The second partition must be 8 MB in size.

  25. Modify the EWF settings so that the first partition of the hard disk is protected. Use either RAM or Disk Overlay.

  26. Check dependencies, build the configuration, download to the target's first partition, and then start the Windows XP Embedded operating system image.

  27. When the Task Manager shell appears, click New Task, and then type CMD in the box.

  28. Click OK.

  29. To check the status of the protected volumes, test Ewfstatus.exe by using the ewfstatus command for C:\windows\system32.

EWFSTATUS - EWF API Example

Copyright (c) 2003 A7 Engineering

--------------------------------------------------------

-- Ewf protected volume configuration

--------------------------------------------------------

DRIVE : C

OVERLAY TYPE : EWF_RAM

CURRENT STATE : EWF_ENABLED

BOOT CMD : EWF_NO_CMD Param1 = 0 Param2 = 0

Example 3: Ewfshell.exe

The Ewfshell application is designed specifically for a system that has a hard disk with one partition that is protected by EWF. Ewfshell.exe has support for the XPEPM APIs to perform shutdown and restart of the Windows XP Embedded system. You must include the Xpepm.dll application as a file resource when a component is created for this type of application.

Part 1: Set up the project

To set up the project:

  1. Open Visual Studio .NET 2003.

  2. On the File menu, click New Project.

  3. In the New Project dialog box, under Project Types, expand Visual C++ Projects, and then click MFC.

  4. Under Templates, click MFC Application.

  5. In the Name box, type EWFShell as shown in Figure 7.

    Figure 7. Opening MFC Application

  6. Click OK.

  7. In the MFC Application Wizard, on the left side, click Application Type.

  8. In the list of options that appear, click Dialog based and Use MFC in a static library. Keep all of the other default options, as shown in Figure 8.

    Figure 8. Setting the application type

  9. On the left side of the wizard, click Advanced Features.

  10. Click to clear the ActiveX controls check box, as shown in Figure 9.

    Figure 9. Clearing ActiveX controls

  11. Click Finish.

  12. Copy Ewfapi.h and Xpepm.h to the directory of the project so that they exist in the same directory as the other project files.

  13. In Solutions Explorer, right-click Source Files, and then click Add Existing Item.

  14. The Open Add Existing Item dialog box should open to the project directory. Select the ewfapi.h file, and then click Open.

  15. Repeat steps 13 and 14 to add the Xpepm.h file. Figure 10 displays the results.

    Figure 10. Adding ewfapi.h and Xpepm.h to the project

  16. Make sure that ewfshellDlg.cpp has focus. You need to add Ewfapi.lib to the project. On the Project menu, click ewfshell Properties.

  17. In ewfshell Property Pages dialog box, you have custom control to build the application. In the Configuration list, select All Configurations.

  18. In the Configuration Properties tree, expand Linker, and then select Input.

  19. Select Additional Dependencies, and then click the box with three dots.

  20. Separately type in the paths to Ewfapi.lib and Xpepm.lib, as shown in Figure 11, and then click OK.

    Figure 11. Adding Ewfapi.lib and Xpepm.lib to the project

  21. Click OK again to close the ewfshell Property Pages dialog box.

Part 2: Complete the application

The next step is to create the interface and then fill in the code. The application should look similar to the application that is displayed in Figure 12.

Figure 12. Ewfshell application

To complete the Ewfshell application:

  1. Create eight buttons for the dialog box.

  2. Add three static text boxes.

  3. Add three text boxes in which a user can type.

  4. Add a group box around the three static text boxes and the three other text boxes. These objects will be used to display the EWF information.

  5. Arrange and resize each object so that your dialog box looks similar to the example that is shown in Figure 12.

  6. Modify the captions and the ID properties for each button, as shown in the following table.

    Table 2. Captions and ID Properties

    Button Caption ID Property
    IDC_Button1 CMD Windows IDC_CMD
    IDC_Button2 Calculator IDC_Calc
    IDC_Button3 App2 IDC_App2
    IDC_Button4 Shutdown IDC_Shutdown
    IDC_Button5 Reboot IDC_ Reboot
    IDC_Button6 EWF Enable IDC_ Enable
    IDC_Button7 EWF Disable IDC_ Disable
    IDC_Button8 EWF Commit IDC_ COMMIT
  7. Edit the properties for the three text boxes in which users can type. Change the ID and make each read-only, as shown in the following table.

    Table 3. ID Properties for Text Boxes

    Box ID Read-only value
    IDC_Edit1 IDC_OTEDIT TRUE
    IDC_Edit2 IDC_STEDIT TRUE
    IDC_Edit3 IDC_CMDEDIT TRUE
  8. Change the captions for the static text boxes and the group box, as shown in the following table.

    Table 4. Captions for Static Text Boxes

    Box Caption
    IDC_STATIC1 Overlay Type
    IDC_STATIC2 EWF Status
    IDC_STATIC3 EWF Command
    IDC_STATIC4 EWF Status

    Each time that Ewfshell.exe runs, the EWF status for drive C will appear in the text boxes. The three EWF buttons are going to perform a basic command on EWF to enable EWF, disable EWF, or commit changes to a protected volume. Each time the button is clicked, a message box appears, indicating the success or failure of the operation. After the message is closed, EWF status is updated. There needs to be a common function that checks and updates the status of EWF. The next few steps create the UpdateEWFStatus() function.

  9. Open EwfshellDlg.h.

  10. In the CefwshellDlg class code, under Protected, add void UpdateEWFStatus() as follows.

    //Implementation
    protected:
       HICON m_hIcon;
    
       void UpdateEWFStatus();
    
       //Generated message map functions
       virtual BOOL OnInitDialog();
       afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
       afx_msg void OnPaint();
       afx_msg HCURSOR OnQueryDragIcon();
       DECLARE_MESSAGE_MAP()
    
  11. Click Save All.

  12. Open EwfshellDlg.cpp.

  13. Add the following code for UpdateEWFStatus() to EwfshellDlg.cpp.

    void CewfshellDlg::UpdateEWFStatus()
    {
       DWORD dwStatus = ERROR_SUCCESS;
       BOOL bResult =FALSE;
       HANDLE hDisk = INVALID_HANDLE_VALUE;;
       PEWF_VOLUME_CONFIG pVolConfig = NULL;
       PEWF_VOLUME_NAME_ENTRY pProVolList = NULL;
       WCHAR szVolumeName[EWF_MAX_DEVICE_NAME_LENGTH + 15] = {0};
       WCHAR szDrive[20];
       swprintf(szDrive, L"\\\\.\\c:");
    
       //Next, open the handle and check for errors.
       hDisk = EwfMgrOpenProtected(szDrive);
    
       pVolConfig = EwfMgrGetProtectedVolumeConfig(hDisk);
    
       switch (pVolConfig->Type)
          {
             case EWF_DISK:      SetDlgItemText(IDC_OTEDIT, 
    "EWF_DISK"); break;
             case EWF_RAM:       SetDlgItemText(IDC_OTEDIT, 
    "EWF_RAM");     break;
             case EWF_RAM_REG:   SetDlgItemText(IDC_OTEDIT, 
    "EWF_RAM_REG"); break;
             default:
             MessageBox("ERROR: Unknown Ewf type", "Error", 
    MB_OK);
             break;
          }
    
       switch (pVolConfig->State)
          {
             case EWF_ENABLED:   SetDlgItemText(IDC_STEDIT, 
    "EWF_ENABLED");  break;
             case EWF_DISABLED:  SetDlgItemText(IDC_STEDIT, 
    "EWF_DISABLED"); break;
             default:
             MessageBox("ERROR: Unknown Ewf state","Error", 
    MB_OK);
             break;
          }
    
       switch (pVolConfig->BootCommand.Command)
          {
             case EWF_NO_CMD:    SetDlgItemText(IDC_CMDEDIT, 
    "EWF_NO_CMD");  break;
             case EWF_ENABLE:    SetDlgItemText(IDC_CMDEDIT, 
    "EWF_ENABLE");  break;
             case EWF_DISABLE:   SetDlgItemText(IDC_CMDEDIT, 
    "EWF_DISABLE");  break;
             case EWF_COMMIT:    SetDlgItemText(IDC_CMDEDIT, 
    "EWF_COMMIT");  break;
             case EWF_SET_LEVEL: SetDlgItemText(IDC_CMDEDIT, 
    "EWF_SET_LEVEL");  break;
             default:
             MessageBox("ERROR: Unknown Ewf command", "Error", 
    MB_OK);   
             break;
          }
    
       //Close the handle and clear pVolConfig.
       LocalFree(pVolConfig);
       pVolConfig = NULL;
       EwfMgrClose(hDisk);
    
    }
    
  14. Add the include statements for Ewfapi.h and Xpepm.h at the top of the EwfshellDlg.cpp code listing, as follows.

    //EwfshellDlg.cpp: implementation file
    //
    
    #include "stdafx.h"
    #include "ewfshell.h"
    #include "ewfshellDlg.h"
    #include ".\ewfshelldlg.h"
    #include "ewfapi.h"extern "C"{#include "xpepm.h"}
    
  15. Now you need UpdateEWFStatus() so that the EWF status function runs every time that the application runs. In EwfshellDlg.cpp, edit the code for BOOL CewfshellDlg::OnInitDialog() and add a call to UpdatedEWFStatus function, as follows.

    BOOL CewfshellDlg::OnInitDialog()
    {
    
       CDialog::OnInitDialog();
    
       //Add the "About..." menu item to the system menu.
    
       //IDM_ABOUTBOX must be in the system command range.
       ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
       ASSERT(IDM_ABOUTBOX < 0xF000);
    
       CMenu* pSysMenu = GetSystemMenu(FALSE);
       if (pSysMenu != NULL)
       {
          CString strAboutMenu;
          strAboutMenu.LoadString(IDS_ABOUTBOX);
          if (!strAboutMenu.IsEmpty())
          {
             pSysMenu->AppendMenu(MF_SEPARATOR);
             pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, 
    strAboutMenu);
          }
       }
    
       //Set the icon for this dialog box. The framework does this
       //automatically when the application's main window is not a
       //dialog box.
       SetIcon(m_hIcon, TRUE);         // Set big icon
       SetIcon(m_hIcon, FALSE);      // Set small icon
    
       UpdateEWFStatus();
    
       return TRUE;  //Return TRUE unless you set the focus to a
       //control.
    }
    
  16. Add the code behind the buttons. Open the IDD_EWFSHELL_DIALOG resource.

  17. Right-click the CMD Window button, and then click Add Event Handler.

  18. The Event Handler Wizard appears (shown in Figure 13). Click BN_CLICKED under Message Type, leave CewfshellDlg selected under Class list, and then click the Add and Edit button.

    Figure 13. Setting up event handler for the CMD Window button

  19. The wizard creates the structure for the OnBnClickedCmd() function. Add the following code.

    void CewfshellDlg::OnBnClickedCmd()
    {
       //Open a Command Prompt window.
       ShellExecute(NULL,"open","c:\\windows\\system32\\cmd.exe",NULL,
    NULL,SW_SHOWNORMAL);
    
    }
    
  20. In the dialog box, right-click the Calculator button, and then click Add Event Handler.

  21. The Event Handler Wizard appears. Click BN_CLICKED under Message Type, leave CewfshellDlg selected under Class list, and then click the Add and Edit button.

  22. The wizard creates the structure for the OnBnClickedCalc() function. Add the following code.

    void CewfshellDlg::OnBnClickedCalc()
    {
       //Open the calculator.
       ShellExecute(NULL,"open","c:\\windows\\system32\\calc.exe",NULL,
    NULL,SW_SHOWNORMAL);
    
    }
    
  23. In the dialog box, right-click the Shutdown button, and then click Add Event Handler.

  24. The Event Handler Wizard appears. Click BN_CLICKED under Message Type, leave CewfshellDlg selected under Class list, and then click the Add and Edit button.

  25. The wizard creates the structure for the OnBnClickedShutdown() function. Add the following code.

    void CewfshellDlg::OnBnClickedShutdown()
    {
       //Add code to shut down Windows XP.
       XPE_Shutdown( );
    
    }
    
  26. In the dialog box, right-click the Reboot button, and then click Add Event Handler.

  27. The Event Handler Wizard appears. Click BN_CLICKED under Message Type, leave CewfshellDlg selected under Class list, and then click the Add and Edit button.

  28. The wizard creates the structure for the OnBnClickedReboot() function. Add the following code.

    void CewfshellDlg::OnBnClickedReboot()
    {
       //Add code to restart Windows XP.
       XPE_ReStart( );
    
    }
    
  29. Click Save All.

  30. In the dialog box, right-click the EWF Enable button, and then click Add Event Handler.

  31. The Event Handler Wizard appears. Click BN_CLICKED under Message Type, leave CewfshellDlg selected under Class list, and then click the Add and Edit button.

  32. The wizard creates the structure for the OnBnClickedEnable() function. Add the following code.

    void CewfshellDlg::OnBnClickedEnable()
    {
    
       HANDLE hDisk;
       WCHAR szDrive[20];
       BOOL bResult =FALSE;
    
       swprintf(szDrive, L"\\\\.\\c:");
    
       //Next, open the handle. 
       hDisk = EwfMgrOpenProtected(szDrive);
    
       bResult = EwfMgrEnable(hDisk);
       if (!bResult)
       {
            MessageBox("EwfMgrEnable failed", "Error", MB_OK);
       }
       else
       {
            MessageBox("EWF Enabled -Reboot system for change to take
     effect", "EWF Enabled", MB_OK);
       }    
    
       EwfMgrClose(hDisk);
    
       UpdateEWFStatus();
    
    }
    
  33. In the dialog box, right-click the EWF Disable button, and then click Add Event Handler.

  34. The Event Handler Wizard appears. Click BN_CLICKED under Message Type, leave CewfshellDlg selected under Class list, and then click the Add and Edit button.

  35. The wizard creates the structure for the OnBnClickedDisable() function. Add the following code.

    void CewfshellDlg::OnBnClickedDisable()
    {
       HANDLE hDisk;
       WCHAR szDrive[20];
       BOOL bResult =FALSE;
    
       swprintf(szDrive, L"\\\\.\\c:");
    
       //Next, open the handle.
       hDisk = EwfMgrOpenProtected(szDrive);      
    
       bResult = EwfMgrDisable(hDisk,FALSE);
       if (!bResult)
       {
          MessageBox("EwfMgrDisable failed", "Error", MB_OK);
       }
       else
       {
          MessageBox("EWF Disabled - Reboot system for change to take
     effect", "EWF Disabled", MB_OK);
       }
    
       EwfMgrClose(hDisk);
       UpdateEWFStatus();
    
    }
    
  36. In the dialog box, right-click the EWF Commit button, and then click Add Event Handler.

  37. The Event Handler Wizard appears. Click BN_CLICKED under Message Type, leave CewfshellDlg selected under Class list, and then click the Add and Edit button.

  38. The wizard creates the structure for the OnBnClickedCommit() function. Add the following code.

    void CewfshellDlg::OnBnClickedCommit()
    {
       HANDLE hDisk;
       WCHAR szDrive[20];
       BOOL bResult =FALSE;
    
       swprintf(szDrive, L"\\\\.\\c:");
    
       //Next, open the handle.
       hDisk = EwfMgrOpenProtected(szDrive);               
    
       bResult = EwfMgrCommit(hDisk);
       if (!bResult)
       {
           MessageBox("EwfMgrCommit failed", "Error", MB_OK);
       }
       else
       {
           MessageBox("Changes commited - Reboot system for change to
     take effect", "EWF Commit", MB_OK);
       }
    
       EwfMgrClose(hDisk);
       UpdateEWFStatus();
    
    }
    
  39. Click Save All.

  40. Build a release version of the application.

Note: The App2 button is for you to modify for your own custom application.

Part 3: Test Ewfshell.exe in a Windows XP Embedded image

To test Ewfshell.exe:

  1. With the application built, create a shell component for Ewfshell.exe and be sure to include Xpepm.dll as a file resource.

  2. Import the component into the database.

  3. Create a Windows XP Embedded configuration by using Target Designer. Be sure that you include the following components:

    • EnableAutoLayout (for more information, see the El Torito topic in Windows XP Embedded Help)
    • EWF Manager Console Application (use this application to test against)
    • Enhanced Write Filter (EWF)
    • EWF API
    • EWF NTLD
    • Minlogon
    • Ewfshell.exe
    • FAT file system
    • NTFS file system
    • Windows Accessories
  4. Make sure that you have imported the PMQ information for the target platform.

    Note: Be sure to add the exact video driver component for your hardware if you want to use the Hibernate and Sleep XPEPM APIs later in EWFSHELL. If you do not do add the exact video driver component, nothing will occur when the application calls these two APIs.

  5. Make sure that your target has a hard disk that is divided into two partitions: one partitioned to use the FAT file system or the NTFS file system and the other left unpartitioned. The second partition must be 8 MB in size.

  6. Modify the EWF settings so that EWF will protect the first partition that is on the target's hard disk. Use either RAM or Disk Overlay.

  7. Check dependencies, build the configuration, download to the target's first partition, and then start the Windows XP Embedded operating system image. When the ewfshell interface appears (shown in Figure 14), the status for drive C is displayed. All of the buttons are functional except App2, which is left for you to use as you want.

    Figure 14. Working ewfshell interface

Conclusion

The preceding examples demonstrate how to create a basic Microsoft Win32® and MFC application. The EWF APIs can also be implemented in other applications that are based on Microsoft Visual C++ .NET, Microsoft Visual C#®, and Microsoft Visual Basic®.

The EWF component in Windows XP Embedded solves many of the problems that developers encountered with the Windows NT Embedded Write Filter component. The ability to programmatically control EWF is an important feature that was introduced in Windows XP Embedded. The EWF APIs provide the flexibly to create a variety of applications, from tools to shells.

References

Windows XP Embedded Advanced, Sean D. Liming, RTC Books, 2003.