Thursday, July 23, 2009

Recursive File Reading in Windows

In Linux command prompt or text mode, we use 'ls -r' for listing files recursively. In th same way, in windows command prompt i think we use 'dir /s' which will list the files present in the given folder and subfolders.

But our question was how to write our own function to read all files present in the folder and subfolder? Because,i think there is no spcific API in windows to print all files present in a folder recursively.

My colleague was written a small program to print files in a directolry using FindFirstFile and FindNextFile APIs of Windows. But that was not printing files in sudirectories .

Hence i thought to achieve our Recursive file searching using the same APIs. Then using file attributes of windows we have done our program. File attribute will be 16 for directories and 32 will be other than directories.

Following Program will print all the files present in the directory, recursively.

void Function()
{
WIN32_FIND_DATA FileData;
HANDLE hSearch;
static RetValue=1;
unsigned char DirPath[300];
unsigned char DirPath_Temp[300];
unsigned int Count=0;
unsigned int Temp=0,Temp_2=0;
unsigned char Temp1[300];
unsigned char *Paths[300];
unsigned int Completed=0;

lstrcpy(DirPath,L"C:\\songs\\*.*");
Completed = 0;
hSearch = FindFirstFile(DirPath, &FileData);
FindNextFileW(hSearch,&FileData);
FindNextFileW(hSearch,&FileData);

while(1)
{
if(FileData.dwFileAttributes == 16 && RetValue != 0)
{
RetValue=1;
printf("directory is %S\n", FileData.cFileName);
Paths[Count] = (char*)malloc(300);
if(!Paths[Count])
{
printf("Malloc failed\n");
return -1;
}
Temp = lstrlen(DirPath);
Temp = Temp*2;
if(DirPath[Temp-2] == '*')
{
Temp = Temp - 6;
}
Temp_2 = 0;
while(Temp)
{
Temp1[Temp_2] = DirPath[Temp_2];
Temp_2++;
Temp--;
}
Temp1[Temp_2]='\0';
Temp1[Temp_2+1]='\0';
lstrcat(Temp1,FileData.cFileName);
lstrcat(Temp1,"\\");
lstrcpy(Paths[Count], Temp1);
Count++;
}
else if(FileData.dwFileAttributes == 32 && RetValue != 0)
{
RetValue=1;
Temp = lstrlen(DirPath);
Temp = Temp*2;
if(DirPath[Temp-2] == '*')
{
Temp = Temp - 6;
}
Temp_2 = 0;
while(Temp)
{
Temp1[Temp_2] = DirPath[Temp_2];
Temp_2++;
Temp--;
}
Temp1[Temp_2]='\0';
Temp1[Temp_2+1]='\0';
lstrcat(Temp1,FileData.cFileName);
printf("File read is %S\n",Temp1);
}
if(!FindNextFile(hSearch, &FileData))
{
if(GetLastError() == ERROR_NO_MORE_FILES)
{
if(Completed == Count)
{
printf("Exiting....\n");
break;
}
lstrcpy(DirPath, Paths[Completed]);
lstrcat(DirPath,"*\0.\0*\0\0\0");
Completed++;
hSearch = FindFirstFile(DirPath, &FileData);
FindNextFileW(hSearch, &FileData);
RetValue = FindNextFileW(hSearch, &FileData);
continue;
}
else
{
printf("Could not find next file.\n");
break;
}
}
}
FindClose(hSearch);
}

Here you can come to know about the single byte and mutli byte(wide) character APIs of windows. By default, windows will take Wide character APIs. It means if u wirte FindFirstFile, it is defined as FindFirstFileW. Here 'W' means wide wide character API.

Also, many of APIs are also available in ASCII ie., Single byte character API. But u have to write explicitly like FindFirstFileA. Here 'A' means ascii or single byte charcter API. Not all APIs are available in ASCII form(single byte).

When we started to implement our own program, we thought that it will take more than a week time. But we have done it within few working hours. This iplementation was given us a great confidence. Because we have started our project without knowing anything about WinCE OS also without any training. Our trainer was/is GOOGLE and MSDN!

Actually, our goal was to achieve this in WinCE 6.0. But Win32 and WinCE are having almost same API set(libraries), we first done this in WinXp and ported the same to WinCE.

Some changes are required in this program to run in WinCE.
1. Remove two FindNextFile statements after FindFirstFile statment
2. Change the path. In WinCE paths will be like /windows/*.*. There is no C, D like drives.

For your reference i will give u this program for WinCE in my next blog. And also i will be explaining this program in my next blog.

Saturday, July 18, 2009

Single Byte Characters and Multi Byte Characters

When we were trying to implement Recursive File reading program in Windows, we were not knowing the concept of Multibyte characters or Wide character. With the help of google search, we were putting 'L' infront of strings. Like
char *ptr= L"Pramod";

We didnt see what the 'L' will do, at the first time. win32 API were executing in downloaded codes. But when we started to do our own implementations, we were using ANSI APIs also in our code. All ANSI C APis were failing!

We have printed the string which is attached with 'L', using for loop. NULL was printing alternatively!

Then we came to know the job of 'L' and TEXT("pramod"); These will put the NULL between alternative characters in the string and make it 'Multibyte characters'.

If i do like, char *ptr="Pramod", in memory it will be 'p0r0a0m0o0d0a00'. Zero will be the alternative character.

Most of ANSI C APIs requires single byte characters. Hence we have written 2 functions for converting Multibyte to Single byte and, Singlebyte to Multibyte.

int ConvertToSingleBytes(char *destpath, char *path)
{
int k,temp1,i;
k=0;
temp1 = lstrlen(path);
i=0;
while(temp1)
{
destpath[i] = path[k];
i++;
k+=2;
temp1--;
}
destpath[i] = '\0';
return 1;
}

Function for Converting SingleByte to MultiByte

int ConvertBackToWide(char*temp_path, char *path)
{
int i, j, h;
h = strlen(path);
i=0; j=0;
while(i < h)
{
temp_path[j]=path[i];
temp_path[j+1] = '\0';
i++; j+=2;
}
temp_path[j] = '\0';
temp_path[j+1] = '\0';
return 0;
}

Also, MultiByte character are called as Wide Characters. And, some ANSI C APIs also has come under wide characters.