Windows CE: C# Application to Format TFAT

Windows CE: C# Application to Format TFAT
Created by samphung on 11/20/2010 10:54:27 PM

Programmatically format Windows CE TFAT file system in C#    


In Windows CE: Formatting TFAT I show how to format a disk with TFAT using C/C++ code. The customer that I wrote that for develops using C#, so I wrote a C# application to test the formatting code. To me, most formatting tools are just too difficult for the average user. In this case, the user will be someone working in the factory or field service. They just need to select a disk and request that it be formatted.

The application dialog looks like:

Fig01

It has a drop down list which I populated with a list of disks, a format button and an exit button. It is simple, and easy to use.

The hard part of this application is populating the drop down list. I did some searching and found suggestion of using System.IO.DirectoryInfo to find the root folders and check the attributes for temporary folders. The following code demonstrates this approach, were DiskSelect is the drop down list:

            System.IO.DirectoryInfo DI = new System.IO.DirectoryInfo(@"\");

 

            System.IO.DirectoryInfo Folders = DI.GetDirectories();

            foreach (System.IO.DirectoryInfo FDI in Folders)

            {

                if (FDI.Attributes.CompareTo(System.IO.FileAttributes.Temporary) == 1)

                    DiskSelect.Items.Add(FDI.Name);

            }

            if( DiskSelect.Items.Count > 0 )

               DiskSelect.SelectedIndex = 0;

This code works and can be effective on some systems. But it has a flaw which is that not all temprary folders are disks. If your OS includes the network redirector component, there will be a Network folder which is temporary but is not a disk. The Release folder which is used in debugging the OS using Platform Builder is also temporary, but not a disk.

The only alternative that I could find is to use FindFirstStore()/FindNextStore() and FindFirstPartition()/FindNextPartition() which are included in StoreAPI. The downside of this approach is that StoreAPI is not generaly included in the SDK and worse, it is not a DLL in the system so it cannot be P/Invoked. So if you don’t have access to the StoreAPI, you might as well stop reading now – the rest of this assumes that you do have access to StoreAPI. If you don’t have it, you might want to ask your OEM for it because it has some valuable functions for accessing disk information.

I could have simply wrapped the StoreAPI with a DLL, which would have been as simple as just linking StoreAPI.lib with a DllEntry() function. But I am not a good enough C# programmer to define the structures needed for C# and I felt that for a C# program the functions are just too clunky. Instead I made some assumptions before writing the code. The assumptions are:

1.    The functions that I will be writing will be used for populating a drop down list and nothing more sophisticated.

2.    The disks have only one partition, if you are working with systems that have multiple partitions you can extend the code to handle that but I didn’t need it.

I realized that I needed to have some data that I could let the application track and pass into function calls. So I started by defining the structure that I needed:

typedef struct __FindDiskInfo__

{

                STOREINFO StoreInfo;

                PARTINFO PartInfo;

} FindDiskInfoT;

STOREINFO and PARTINFO are defined in storemgr.h which is included in the SDK. I plan to create functions that populate the structure and then some functions to get the strings that I need. This should make the C# fairly easy to write. The first step is to initalize the structure and get a pointer/reference from the C/C++ code to the C# code. NewStoreInfo() will allocate the storage and initialize it and DeleteStoreInfo() will release the structure:

__declspec(dllexport) FindDiskInfoT * APIENTRY NewStoreInfo()

{

                FindDiskInfoT *FindDiskInfo;

                RETAILMSG( 1, (TEXT("NewStoreInfo\n")));

                FindDiskInfo = (FindDiskInfoT *)malloc( sizeof(FindDiskInfoT) );

                if( FindDiskInfo == NULL )

                {

                                RETAILMSG( 1, (TEXT("StartFindStore: malloc failed\n")));

                                return NULL;

                }

                memset(FindDiskInfo, 0, sizeof(FindDiskInfoT));

                FindDiskInfo->StoreInfo.cbSize = sizeof(STOREINFO);

                FindDiskInfo->PartInfo.cbSize = sizeof(PARTINFO);

                                wcscpy(FindDiskInfo->PartInfo.szVolumeName, TEXT("TEST VolName"));

 

                RETAILMSG( 1, (TEXT("NewStoreInfo return %X\n"), FindDiskInfo));

                return FindDiskInfo;

}

 

__declspec(dllexport) BOOL APIENTRY DeleteStoreInfo(HANDLE hFind, FindDiskInfoT *FindDiskInfo)

{

                if( FindDiskInfo != NULL )

                {

                                free( FindDiskInfo );

                }

                if( hFind )

                {

                                FindCloseStore( hFind );

                }

                return TRUE;

}

And the C# call to these functions are:

IntPtr StoreInfo;

 

StoreInfo = NewStoreInfo();

DeleteStoreInfo(hStore, StoreInfo);

Note that DeleteStoreInfo() has an hStore passed into into it. hStore is HANDLE used for finding the disks. hStore is returned from StartFindDisk() which is called to start finding available disks. StartFindDisk() receives a pointer to the previously allocated FindDiskInfoT:

__declspec(dllexport) HANDLE APIENTRY StartFindDisk( FindDiskInfoT *FindDiskInfo )

{

HANDLE hFind = INVALID_HANDLE_VALUE;

 

                hFind = FindFirstStore(&(FindDiskInfo->StoreInfo));

               

                if( hFind != INVALID_HANDLE_VALUE )

                {

                                HANDLE hStore;

                                hStore = OpenStore( FindDiskInfo->StoreInfo.szDeviceName );               

 

                                if( hStore )

                                {

                                                HANDLE hFind = INVALID_HANDLE_VALUE;

                                                hFind = FindFirstPartition(hStore, &(FindDiskInfo->PartInfo));

 

                                                if(INVALID_HANDLE_VALUE != hFind)

                                                {

                                                                FindClose(hFind);

                                                }

                                                else

                                                                RETAILMSG( 1, (TEXT("No Partitions Found\n")));

                                                CloseHandle(hStore);

                                }

                                else

                                                RETAILMSG(1, (TEXT("OpenSelectedStore failed\n")));

                }

                else

                {

                                RETAILMSG( 1, (TEXT("StartFindStore: FindFirstStore failed %d\n"), GetLastError()));

                }

               

                return hFind;

}

And the C# call is:

            hStore = StartFindDisk(StoreInfo);

StartFindDisk() finds the first available disk and the first partition on the disk and populates the FindDiskInfoT structure with the available information for use later. After calling this, to get the name of the folder, the device name and the partition name, the following functions can be used:

__declspec(dllexport) TCHAR * APIENTRY GetStoreDeviceName( FindDiskInfoT *FindDiskInfo )

{

                TCHAR * RetVal = NULL;

                if( FindDiskInfo )

                {

                                RetVal = FindDiskInfo->StoreInfo.szDeviceName;

                }

                return RetVal;

}

 

__declspec(dllexport) TCHAR * APIENTRY GetStoreFolderName( FindDiskInfoT *FindDiskInfo )

{

                TCHAR * RetVal = NULL;

                if( FindDiskInfo )

                {

                                RetVal = FindDiskInfo->PartInfo.szVolumeName;

                }

                return RetVal;

}

 

__declspec(dllexport) TCHAR * APIENTRY GetStorePartitionName( FindDiskInfoT *FindDiskInfo )

{

                TCHAR * RetVal = NULL;

                if( FindDiskInfo )

                {

                                RetVal = FindDiskInfo->PartInfo.szPartitionName;

                }

                return RetVal;

}

Then to get the rest of the disks, FindNextDisk() is used:

__declspec(dllexport) BOOL APIENTRY FindNextDisk( HANDLE hFind, FindDiskInfoT *FindDiskInfo )

{

BOOL FindResult = FALSE;

 

                if( FindDiskInfo == NULL || hFind == INVALID_HANDLE_VALUE )

                {

                                                RETAILMSG( 1, (TEXT("FindNextDisk: invalid parameters\n")));

                                                return FALSE;

                }

                FindResult = FindNextStore(hFind, &(FindDiskInfo->StoreInfo));

               

                if( FindResult != FALSE )

                {

                                HANDLE hStore;

                                hStore = OpenStore( FindDiskInfo->StoreInfo.szDeviceName );               

 

                                if( hStore )

                                {

                                                HANDLE hFind = INVALID_HANDLE_VALUE;

                                                memset( &(FindDiskInfo->PartInfo), 0, sizeof(PARTINFO));

                                                FindDiskInfo->PartInfo.cbSize = sizeof(PARTINFO);

 

                                                hFind = FindFirstPartition(hStore, &(FindDiskInfo->PartInfo));

 

                                                if(INVALID_HANDLE_VALUE != hFind)

                                                {

                                                                FindClose(hFind);

                                                }

                                                else

                                                {

                                                                RETAILMSG( 1, (TEXT("FindNextDisk: No Partitions Found %d\n"), GetLastError()));

                                                                FindResult = FALSE;

                                                }

                                                CloseHandle(hStore);

                                }

                                else

                                {

                                                RETAILMSG(1, (TEXT("FindNextDisk: OpenSelectedStore failed\n")));

                                                FindResult = FALSE;

                                }

                }

                else

                {

                                RETAILMSG( 1, (TEXT("FindNextDisk: FindNextStore failed %d\n"), GetLastError()));

                                FindResult = FALSE;

                }

               

                return FindResult;

}

Similar to StartFindDisk() this finds the next disk and its first partition and populates the FindDiskInfoT with the available data, so that the strings can be retreived later.

The code for setting up the C# dialog looks like:

       

        static extern bool FormatDiskTFAT(String StoreName, String PartitionName);

       

        static extern bool FormatDiskTFATEx(String FolderName);

       

        static extern IntPtr StartFindDisk(IntPtr pStoreInfo);

       

        static extern bool DeleteStoreInfo(IntPtr hStore, IntPtr FindDiskInfo);

       

        static extern bool FindNextDisk(IntPtr hFind, IntPtr pStoreInfo);

       

        static extern IntPtr GetStoreDeviceName(IntPtr pStoreInfo);

       

        static extern IntPtr GetStoreFolderName(IntPtr pStoreInfo);

       

        static extern IntPtr GetStorePartitionName(IntPtr pStoreInfo);

       

        static extern IntPtr NewStoreInfo();

 

        DiskInfo Disks;

 

        public FormatTool()

        {

            IntPtr StoreInfo;

            IntPtr hStore;

            IntPtr ipName;

            int DiskCount = 0;

 

            InitializeComponent();

          

            StoreInfo = NewStoreInfo();

            hStore = StartFindDisk(StoreInfo);

 

            if (hStore != null)

            {

                Disks = new DiskInfo[1];

                Disks[DiskCount] = new DiskInfo();

 

                ipName = GetStoreDeviceName(StoreInfo);

                Disks[DiskCount].DeviceName = Marshal.PtrToStringUni(ipName).ToString();

 

                ipName = GetStoreFolderName(StoreInfo);

                Disks[DiskCount].FolderName = Marshal.PtrToStringUni(ipName).ToString();

 

                ipName = GetStorePartitionName(StoreInfo);

                Disks[DiskCount].PartitionName = Marshal.PtrToStringUni(ipName).ToString();

 

                DiskSelect.Items.Add(Disks[DiskCount].FolderName);

                DiskSelect.SelectedIndex = 0;

                DiskCount++;

 

                while (FindNextDisk(hStore, StoreInfo))

                {

                    DiskInfo NewDisks = new DiskInfo[DiskCount+1];

                    Disks.CopyTo(NewDisks, 0);

                    NewDisks[DiskCount] = new DiskInfo();

 

                    ipName = GetStoreDeviceName(StoreInfo);

                    NewDisks[DiskCount].DeviceName = Marshal.PtrToStringUni(ipName).ToString();

 

                    ipName = GetStoreFolderName(StoreInfo);

                    NewDisks[DiskCount].FolderName = Marshal.PtrToStringUni(ipName).ToString();

 

                    ipName = GetStorePartitionName(StoreInfo);

                    NewDisks[DiskCount].PartitionName = Marshal.PtrToStringUni(ipName).ToString();

 

                    DiskSelect.Items.Add(NewDisks[DiskCount].FolderName);

                    DiskCount++;

                    Disks = NewDisks;

                }

                DeleteStoreInfo(hStore, StoreInfo);

                if (DiskSelect.Items.Count > 0)

                    DiskSelect.SelectedIndex = 0;

            }

            

        }

I probably could have simplified this code, and if it were a long term project I would spend time on that.   This cod uses a class for keeping track of the disk information for use in the call to FormatDiskTFAT:

    public class DiskInfo

    {

        public String FolderName;

        public String DeviceName;

        public String PartitionName;

    }

But in hindsight I wrote FormatDiskTFATEx() which doesn’t need all of that information. So the code can be simplified to:

            String DiskName;

            StoreInfo = NewStoreInfo();

            hStore = StartFindDisk(StoreInfo);

 

            if (hStore != null)

            {

                ipName = GetStorePartitionName(StoreInfo);

                DiskName = Marshal.PtrToStringUni(ipName).ToString();

 

                DiskSelect.Items.Add(DiskName);

                DiskSelect.SelectedIndex = 0;

 

                while (FindNextDisk(hStore, StoreInfo))

                {

                    ipName = GetStorePartitionName(StoreInfo);

                    DiskName = Marshal.PtrToStringUni(ipName).ToString();

 

                    DiskSelect.Items.Add(DiskName);

                }

                DeleteStoreInfo(hStore, StoreInfo);

                if (DiskSelect.Items.Count > 0)

                    DiskSelect.SelectedIndex = 0;

            }

Finally, when the Format button is pressed we need to format the disk. The button handler is:

        private void FormatButton_Click(object sender, EventArgs e)

        {

            int Index = DiskSelect.SelectedIndex;

 

            Exitbutton.Visible = false;

            FormatButton.Visible = false;

            Formatinglabel.Text = "Formatting, Please Wait";

            Formatinglabel.Visible = true;

            this.Refresh();

 

            System.Threading.Thread.Sleep(2000); 

            FormatDiskTFAT(Disks[Index].DeviceName, Disks[Index].PartitionName);

 

            Exitbutton.Visible = true;

            FormatButton.Visible = true;

            Formatinglabel.Text = "Formatting Complete";

            Formatinglabel.Visible = true;

            this.Refresh();

        }

Which uses FormatDiskTFAT(), but FormatDiskTFATEx() can be used as:

            FormatDiskTFATEx(DiskSelect.SelectedItem.ToString());

FormatButton_Click() hides the buttons and puts a message in a static text box to tell the user to wait then formats the disk. After the disk is formatted, it changes the text to Format Complete and puts the buttons back in. The problem that I found is that the format can be very quick, too quick so that the message isn’t displayed and the buttons aren’t removed. So I added a 2 second delay just to let the user know that something happened.

 

 

Note:  This article is written by Bruce Eitman, and is posted to the Embedded101 site with Bruce’s permission

Copyright © 2010 – Bruce Eitman

http://geekswithblogs.net/BruceEitman/

Embedded101 Articles

Click to Expand/Collapse Groups
Skip Navigation Links.
Collapse Windows Embedded Compact (CE)Windows Embedded Compact (CE)
Collapse Compact 7Compact 7
Build A Windows Network Projector wi...
Filter Device Drivers
Asynchronous I/O request support
Configure Flash Storage to Launch Co...
CEDriverWiz V2.00: About this releas...
Installing CEDriverWiz for Visual St...
Collapse CE 6.0CE 6.0
Stream Driver with CEDriverWiz rev 0...
Connecting Visual Studio IDE to CE 6...
Windows CE: Save and Restore the Re...
Windows CE: Stream Interface Driver...
Windows CE: Persisting Registry Chan...
Windows CE: Enhanced BusEnum
Windows CE: Soft Reset
Windows CE: Reading a String from th...
Windows CE: Displaying Disk Informa...
Windows CE: Formatting TFAT
Windows CE: C# Application to Format...
Hive-Based Registry for CE 6.0
AutoLaunch for CE 6.0
Configure Flash Storage to Launch Co...
CEDriverWiz V2.00: About this releas...
Installing CEDriverWiz for Visual St...
Collapse CE 5.0CE 5.0
Configure Flash Storage to Launch Co...
Collapse Platform Builder & OS DesignPlatform Builder & OS Design
Platform Builder: Automatically Flus...
Windows CE: Enhanced BusEnum
Windows CE: Soft Reset
Windows CE: Displaying Disk Informa...
Build A Windows Network Projector wi...
CEDriverWiz V2.00: About this releas...
Installing CEDriverWiz for Visual St...
Collapse BSP, OAL & BootloaderBSP, OAL & Bootloader
Windows CE 6.0: User Mode KernelIoC...
Windows CE: Displaying Disk Informa...
Collapse RegistryRegistry
Platform Builder: Automatically Flus...
Windows CE: Save and Restore the Re...
Windows CE: Stream Interface Driver...
Windows CE: Persisting Registry Chan...
Windows CE: Reading a String from th...
Hive-Based Registry for CE 6.0
Collapse Device DriverDevice Driver
Stream Driver with CEDriverWiz rev 0...
Windows CE: Stream Interface Driver...
Windows CE: Enhanced BusEnum
CEDriverWiz V2.00: About this releas...
Installing CEDriverWiz for Visual St...
Collapse File SystemFile System
Windows CE: Formatting TFAT
Windows CE: C# Application to Format...
Collapse Application DevelopmentApplication Development
Connecting Visual Studio IDE to CE 6...
Windows CE: Persisting Registry Chan...
Windows CE: Reading a String from th...
Windows CE: Formatting TFAT
Windows CE: C# Application to Format...
AutoLaunch for CE 6.0
Windows CE: Stream Interface Driver ...
IBW & ICE
Stream Driver with CEDriverWiz rev 0...
Connecting Visual Studio IDE to CE 6...
Platform Builder: Automatically Flus...
Windows CE: Save and Restore the Re...
Windows CE: Stream Interface Driver...
Windows CE: Persisting Registry Chan...
Windows CE: Enhanced BusEnum
Windows CE: Reading a String from th...
Windows CE: Displaying Disk Informa...
Windows CE: Formatting TFAT
Windows CE: C# Application to Format...
Build A Windows Network Projector wi...
Hive-Based Registry for CE 6.0
AutoLaunch for CE 6.0
Hello all
Filter Device Drivers
Asynchronous I/O request support
Configure Flash Storage to Launch Co...
CEDriverWiz Version 2.00 User Manual
CEDriverWiz V2.00: About this releas...
Installing CEDriverWiz for Visual St...
CEDriverWiz Version 2.00: An Example
CEDriverWiz Version 2.00: Using the ...
Collapse Windows Embedded StandardWindows Embedded Standard
WES7
WES-2009
Windows XP Embedded
Target Designer
Enhanced Write Filter
Collapse NET Compact FrameworkNET Compact Framework
Windows CE: C# Application to Format...
Windows Phone 7
Misc.
Turkish porno izle video site in rokettubeporno izle