|< C & Win32 programming 3 | Main | C & Win32 programming 5 >| Site Index | Download |


 

 

 

 

MODULE D1

WIN32 AND C PROGRAMMING 4

 

 

 

 

What are in this Module?

  1. Obtaining and Setting File Information

  2. Searching for One or More Files

  3. Members

  4. Retrieving and Changing File Attributes

  5. Retrieving File Type Information

  6. Determining a File Size

 

 

My Training Period: zz hours. Before you begin, read some instruction here.

 

The Win32 C programming skills:

  • Be familiar and play around with the Win32 programming.

  • Able to understand the Windows file system (NTFS), directory and file.

  • Able to find and collect information about file management functions.

  • Able to understand and use the collected information about the functions in programs.

Obtaining and Setting File Information: Searching for One or More Files

  • An application can search the current directory for all file names that match a given pattern by using the FindFirstFile(), FindFirstFileEx(), FindNextFile(), and FindClose() functions.  The pattern must be a valid file name and can include wildcard characters.

  • The FindFirstFile() and FindFirstFileEx() functions create handles that FindFirstFileEx() uses to search for other files with the same pattern.

  • All functions return information about the file that was found.  This information includes the file name, size, attributes, and time.

  • The FindFirstFileEx() function also allows an application to search for files based on additional search criteria.  The function can limit searches to device names or directory names.

  • The FindClose() function destroys handles created by FindFirstFile() and FindFirstFileEx().

  • An application can search for a single file on a specific path by using the SearchPath() function.

  • The following Table lists the needed information in order to use the FindFirstFile() function.

Information

Description

The function

FindFirstFile().

The use

Searches a directory for a file or subdirectory whose name matches the specified name.  To specify additional attributes to be used in the search, use the FindFirstFileEx() function.

The prototype

HANDLE FindFirstFile(LPCTSTR lpFileName, LPWIN32_FIND_DATA lpFindFileData);

Example

WIN32_FIND_DATA FileData;

 

FindFirstFile("*.txt", &FileData);

The parameters

lpFileName - [in] Pointer to a null-terminated string that specifies a valid directory or path and file name, which can contain wildcard characters (* and ?).  If the string ends with a wildcard, a period, or a directory name, the user must have access to the root and all subdirectories on the path.

In the ANSI version of this function, the name is limited to MAX_PATH characters.  To extend this limit to 32,767 wide characters, call the Unicode version of the function and prepend "\\?\" to the path.

 

lpFindFileData - [out] Pointer to the WIN32_FIND_DATA structure that receives information about the found file or subdirectory.

The return value

If the function succeeds, the return value is a search handle used in a subsequent call to FindNextFile() or FindClose().  If the function fails, the return value is INVALID_HANDLE_VALUE.  To get extended error information, call GetLastError().

The header file

<windows.h>

 

Table 8:  FindFirstFile() information.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Information

Description

The function

FindNextFile().

The use

Continues a file search from a previous call to the FindFirstFile() or FindFirstFileEx() function.

The prototype

BOOL FindNextFile( HANDLE   hFindFile, LPWIN32_FIND_DATA   lpFindFileData );

Example

WIN32_FIND_DATA FileData;

HANDLE hSearch;

 

hSearch = FindFirstFile("*.txt", &FileData);

FindNextFile(hSearch, &FileData);

The parameters

hFindFile - [in] Search handle returned by a previous call to the FindFirstFile() or FindFirstFileEx() function.

lpFindFileData - [out] Pointer to the WIN32_FIND_DATA structure that receives information about the found file or subdirectory.  The structure can be used in subsequent calls to FindNextFile() to see the found file or directory.

The return value

If the function succeeds, the return value is nonzero. If the function fails, the return value is zero.  To get extended error information, call GetLastError().  If no matching files can be found, the GetLastError() function returns ERROR_NO_MORE_FILES.

The header file

<windows.h>

 

Table 9:  FindNextFile() information.

Information

Description

The function

FindClose().

The use

Closes a file search handle opened by the FindFirstFile(), FindFirstFileEx(), or FindFirstStreamW() function.

The prototype

BOOL FindClose(HANDLE  hFindFile);

Example

WIN32_FIND_DATA FileData;

HANDLE hSearch;

 

hSearch = FindFirstFile("*.txt", &FileData);

FindClose(hSearch);

The parameters

hFindFile - [in, out] File search handle.

The return value

If the function succeeds, the return value is nonzero.  If the function fails, the return value is zero.  To get extended error information, call GetLastError().

The header file

<windows.h>

 

Table 10:  FindClose() information

typedef struct _WIN32_FIND_DATA {

    DWORD dwFileAttributes;

    FILETIME ftCreationTime;

    FILETIME ftLastAccessTime;

    FILETIME ftLastWriteTime;

    DWORD nFileSizeHigh;

    DWORD nFileSizeLow;

    DWORD dwReserved0;

    DWORD dwReserved1;

    TCHAR cFileName[MAX_PATH];

    TCHAR cAlternateFileName[14];

} WIN32_FIND_DATA, *PWIN32_FIND_DATA;

Members

dwFileAttributes - File attributes of the file found.  This member can be one or more of the following values.

Attribute

Meaning

FILE_ATTRIBUTE_ARCHIVE

The file or directory is an archive file or directory. Applications use this attribute to mark files for backup or removal.

FILE_ATTRIBUTE_COMPRESSED

The file or directory is compressed.  For a file, this means that all of the data in the file is compressed.  For a directory, this means that compression is the default for newly created files and subdirectories.

FILE_ATTRIBUTE_DIRECTORY

The handle identifies a directory.

FILE_ATTRIBUTE_ENCRYPTED

The file or directory is encrypted.  For a file, this means that all data in the file is encrypted.  For a directory, this means that encryption is the default for newly created files and subdirectories.

FILE_ATTRIBUTE_HIDDEN

The file or directory is hidden.  It is not included in an ordinary directory listing.

FILE_ATTRIBUTE_NORMAL

The file or directory has no other attributes set. This attribute is valid only if used alone.

FILE_ATTRIBUTE_OFFLINE

The file data is not immediately available.  This attribute indicates that the file data has been physically moved to offline storage.  This attribute is used by Remote Storage, the hierarchical storage management software.  Applications should not arbitrarily change this attribute.

FILE_ATTRIBUTE_READONLY

The file or directory is read-only.  Applications can read the file but cannot write to it or delete it. In the case of a directory, applications cannot delete it.

FILE_ATTRIBUTE_REPARSE_POINT

The file or directory has an associated reparse point.

FILE_ATTRIBUTE_SPARSE_FILE

The file is a sparse file.

FILE_ATTRIBUTE_SYSTEM

The file or directory is part of the operating system or is used exclusively by the operating system.

FILE_ATTRIBUTE_TEMPORARY

The file is being used for temporary storage.  File systems attempt to keep all of the data in memory for quicker access, rather than flushing it back to mass storage.  A temporary file should be deleted by the application as soon as it is no longer needed.

 

Table 11:  dwFileAttributes values.

ftCreationTime - A FILETIME structure that specifies when the file or directory was created.  If the underlying file system does not support creation time, this member is zero.

ftLastAccessTime - A FILETIME structure.  For a file, the structure specifies when the file was last read from or written to. For a directory, the structure specifies when the directory was created. If the underlying file system does not support last access time, this member is zero.

On FAT, the specified date for both files and directories will be correct, but the time of day will always be set to midnight.

ftLastWriteTime - A FILETIME structure. For a file, the structure specifies when the file was last written to. For a directory, the structure specifies when the directory was created. If the underlying file system does not support last write time, this member is zero.

nFileSizeHigh - High-order DWORD value of the file size, in bytes.  This value is zero unless the file size is greater than MAXDWORD.  The size of the file is equal to (nFileSizeHigh * (MAXDWORD+1)) + nFileSizeLow.

nFileSizeLow - Low-order DWORD value of the file size, in bytes.

dwReserved0 - If the dwFileAttributes member includes the FILE_ATTRIBUTE_REPARSE_POINT attribute, this member specifies the reparse tag.  Otherwise, this value is undefined and should not be used.

dwReserved1 - Reserved for future use.

cFileName - A null-terminated string that specifies the name of the file.

cAlternateFileName - A null-terminated string that specifies an alternative name for the file.  This name is in the classic 8.3 (filename.ext) file name format.

Retrieving and Changing File Attributes

Information

Description

The function

GetFileAttributes().

The use

Retrieves a set of FAT-style attributes for the specified file or directory.  To obtain additional attribute information, use the GetFileAttributesEx() function.

The prototype

DWORD GetFileAttributes(LPCTSTR lpFileName);

Example

WIN32_FIND_DATA FileData;

 

GetFileAttributes(FileData.cFileName);

The parameters

lpFileName - [in] Pointer to a null-terminated string that specifies the name of a file or directory.

In the ANSI version of this function, the name is limited to MAX_PATH characters.  To extend this limit to 32,767 wide characters, call the Unicode version of the function and prepend "\\?\" to the path.

The return value

If the function succeeds, the return value contains the attributes of the specified file or directory.  If the function fails, the return value is INVALID_FILE_ATTRIBUTES.  To get extended error information, call GetLastError().

The header file

<windows.h>

 

Table 12:  GetFileAttributes() information.

#include <windows.h>

#include <stdio.h>

 

int main()

{

WIN32_FIND_DATA FileData;

HANDLE hSearch;

DWORD dwAttrs;

char szDirPath[] = "G:\\newdir\\";

char szNewPath[MAX_PATH];

BOOL fFinished = FALSE;

 

// create a new directory. If something wrong

if(!CreateDirectory(szDirPath, NULL))

{

printf("Could not create %s directory.\n", szDirPath);

 // just exit

exit (0);

}

else

printf("%s directory successfully created.\n", szDirPath);

 

// start searching for .txt files in the current directory.

// failed when tested with a path...need to change the current working directory???

hSearch = FindFirstFile("*.txt", &FileData);

if(hSearch == INVALID_HANDLE_VALUE)

{

    printf("No .txt files found lol.\n");

    //just exit

    exit (0);

}

 

// copy each .txt file to the new directory and change it to read only, if not already.

while(!fFinished)

// copies a string in szDirPath to szNewPath buffer...

   lstrcpy(szNewPath, szDirPath);

   // appends the filename to the path...

   lstrcat(szNewPath, FileData.cFileName);

 

   // in the buffer, do the file copy...

    if(CopyFile(FileData.cFileName, szNewPath, FALSE))

   {

      printf("%s file successfully copied.\n", FileData.cFileName);

      // and gets the file attribute...

      dwAttrs = GetFileAttributes(FileData.cFileName);

      // change to read only where applicable...

      if(!(dwAttrs & FILE_ATTRIBUTE_READONLY))

        SetFileAttributes(szNewPath, dwAttrs | FILE_ATTRIBUTE_READONLY);

   }

   else

       printf("Could not copy %s file.\n", FileData.cFileName);

    if(!FindNextFile(hSearch, &FileData))

    {

        if(GetLastError() == ERROR_NO_MORE_FILES)

        {

            printf("No more file lol!\n");

            fFinished = TRUE;

        }

        else

           printf("Could not find next file.\n");

     }

}

// close the search handle.

FindClose(hSearch);

return 0;

}

The output:

 

G:\newdir\ directory successfully created.

module15.txt file successfully copied.

module16.txt file successfully copied.

module17.txt file successfully copied.

module18.txt file successfully copied.

module19.txt file successfully copied.

module20.txt file successfully copied.

module21.txt file successfully copied.

No more file lol!

Press any key to continue

Information

Description

The function

SearchPath().

The use

Searches for the specified file in the specified path.

The prototype

DWORD SearchPath( LPCTSTR lpPath, LPCTSTR lpFileName, LPCTSTR lpExtension, DWORD nBufferLength, LPTSTR  lpBuffer, LPTSTR* lpFilePart );

Example

char PathName[50] = "C:\\ ";

char fname[20] = "testfile.txt";

char lpBuffer[500];

LPSTR *lpFilePart;

 

SearchPath(PathName, fname, NULL, 500, lpBuffer, lpFilePart);

The parameters

lpPath - [in] Pointer to a null-terminated string that specifies the path to be searched for the file.  If this parameter is NULL, the function searches for a matching file in the following directories in the following sequence:

  1. The directory from which the application loaded.
  2. The current directory.
  3. The system directory.  Use the GetSystemDirectory() function to get the path of this directory.
  4. The 16-bit system directory.  There is no function that retrieves the path of this directory, but it is searched.
  5. The Windows directory.  Use the GetWindowsDirectory() function to get the path of this directory.
  6. The directories that are listed in the PATH environment variable.

 

lpFileName - [in] Pointer to a null-terminated string that specifies the name of the file to search for.

lpExtension - [in] Pointer to a null-terminated string that specifies an extension to be added to the file name when searching for the file.  The first character of the file name extension must be a period (.).  The extension is added only if the specified file name does not end with an extension. If a file name extension is not required or if the file name contains an extension, this parameter can be NULL.

nBufferLength - [in] Size of the buffer that receives the valid path and file name, in TCHARs.

lpBuffer - [out] Pointer to the buffer that receives the path and file name of the file found.

lpFilePart - [out] Pointer to the variable that receives the address (within lpBuffer) of the last component of the valid path and file name, which is the address of the character immediately following the final backslash (\) in the path.

The return value

If the function succeeds, the value returned is the length, in TCHARs, of the string copied to the buffer, not including the terminating null character.  If the return value is greater than nBufferLength, the value returned is the size of the buffer required to hold the path.

If the function fails, the return value is zero.  To get extended error information, call GetLastError().

The header file

<windows.h>

 

Table 13:  SearchPath() information.

#include <windows.h>

#include <stdio.h>

 

char lpBuffer[500];

LPSTR *lpFilePart;

 

int main(int argc, char *argv[ ])

{

// if not enough arguments supplied 

if(argc != 3)

{

       printf("Usage: %s <path> <filename.ext>\n", argv[0]);

       exit (1);

}

 

  DWORD test = SearchPath(

  argv[1],

  argv[2],

  NULL,

  500,

  lpBuffer,

  lpFilePart);

  // if something wrong to the SearchPath()

  if(!test)

  {

         printf("%s file not found!\n", argv[2]);

         exit (1);

  }

  // display the result...

  else

  {

   printf("The return value is: %d, error: %d\n", test, GetLastError());

   printf("The path is %s\n", lpBuffer);

   printf("The path is %p\n", lpFilePart);

  }

return 0;

}

 

The output:

G:\vcnetprojek\win32prog\Debug>win32prog

Usage: win32prog <path> <filename.ext>

 

G:\vcnetprojek\win32prog\Debug>win32prog G:\

Usage: win32prog <path> <filename.ext>

 

G:\vcnetprojek\win32prog\Debug>win32prog G:\ testfile.txt

testfile.txt file not found!

G:\vcnetprojek\win32prog\Debug>win32prog C:\ testfile.txt

The return value is: 15, error: 0

The path is C:\testfile.txt

The path is 00000000

 

G:\vcnetprojek\win32prog\Debug>

 

Retrieving File Type Information

Information

Description

The function

GetFileType().

The use

Retrieves the file type of the specified file.

The prototype

DWORD GetFileType(HANDLE hFile);

Example

HANDLE hFile;

hFile = CreateFile(...);

 

GetFileType(hFile);

The parameters

hFile - [in] Handle to an open file.

The return value

The return value is one of the following values:

  1. FILE_TYPE_CHAR - The specified file is a character file, typically an LPT device or a console.

  2. FILE_TYPE_DISK - The specified file is a disk file.

  3. FILE_TYPE_PIPE - The specified file is a socket, a named pipe, or an anonymous pipe.

  4. FILE_TYPE_REMOTE - Unused.

  5. FILE_TYPE_UNKNOWN - Either the type of the specified file is unknown, or the function failed.

The header file

<windows.h>

 

Table 14:  GetFileType() information.

Information

Description

The function

GetBinaryType().

The use

Determines whether a file is executable, and if so, what type of executable file it is. That last property determines which subsystem an executable file runs under.

The prototype

BOOL GetBinaryType(LPCTSTR lpApplicationName, LPDWORD lpBinaryType);

Example

DWORD lpBinaryType[100];

char fname2[30] = "c:\\windows\\NOTEPAD.EXE";

 

GetBinaryType(fname2, lpBinaryType);

The parameters

lpApplicationName - [in] Pointer to a null-terminated string that contains the full path of the file whose binary type is to be determined. In the ANSI version of this function, the name is limited to MAX_PATH characters.  To extend this limit to 32,767 wide characters, call the Unicode version of the function and prepend "\\?\" to the path.

lpBinaryType - [out] Pointer to a variable to receive information about the executable type of the file specified by lpApplicationName. The following constants are defined:

  1. SCS_32BIT_BINARY - A 32-bit Windows-based application.

  2. SCS_64BIT_BINARY - A 64-bit Windows-based application.

  3. SCS_DOS_BINARY - An MS-DOS – based application.

  4. SCS_OS216_BINARY - A 16-bit OS/2-based application.

  5. SCS_PIF_BINARY - A PIF file that executes an MS-DOS – based application.

  6. SCS_POSIX_BINARY - A POSIX based application.

  7. SCS_WOW_BINARY - A 16-bit Windows-based application.

The return value

If the file is executable, the return value is nonzero.  The function sets the variable pointed to by lpBinaryType to indicate the file's executable type.  If the function is not executable, or if the function fails, the return value is zero.  To get extended error information, call GetLastError().

The header file

<windows.h>

 

Table 15:  GetBinaryType() information.

#include <windows.h>

#include <stdio.h>

 

int main()

{

// handle for file

HANDLE hFile;

DWORD lpBinaryType[100];

// file and path

char fname[20] = "c:\\test.doc";

char fname2[30] = "c:\\windows\\NOTEPAD.EXE";

 

hFile = CreateFile(fname,        // file to be opened

                GENERIC_READ,    // open for reading

                FILE_SHARE_READ, // share for reading

                NULL,            // default security

                OPEN_EXISTING,   // open existing file

                FILE_ATTRIBUTE_READONLY, // the file is read only

                NULL);           // no attribute template

if(hFile == INVALID_HANDLE_VALUE)

    printf("Could not open %s file, error %d\n", fname, GetLastError());

printf("File's HANDLE is OK!\n");

 

if(GetFileType(hFile) == 0)

       printf("The %s file is character type.\n", fname);

else if (GetFileType(hFile) == 1)

       printf("The %s file is disk file.\n", fname);

else if (GetFileType(hFile) == 2)

       printf("The %s file is socket or named pipe.\n", fname);

else if (GetFileType(hFile) == 4)

       printf("The %s file is UNKNOWN type or GetFileType() failed!\n", fname);

CloseHandle(hFile);

if(GetBinaryType(fname2, lpBinaryType) != 0)

       printf("The %s file is executable.\n", fname2);

else

       printf("The %s is file non-executable.\n", fname2);

return 0;

}

 

The output:

 

File's HANDLE is OK!

The c:\test.doc file is disk file.

The c:\windows\NOTEPAD.EXE file is executable.

Press any key to continue

Determining a File Size

Information

Description

The function

GetFileSize().

The use

Retrieves the size of the specified file. The file size that can be reported by this function is limited to a DWORD value.

The prototype

DWORD GetFileSize(HANDLE  hFile, LPDWORD  lpFileSizeHigh);

Example

hFile1 = CreateFile(...);

 

GetFileSize(hFile1, NULL);

The parameters

hFile - [in] Handle to the file whose size is to be returned. This handle must have been created with either the GENERIC_READ or GENERIC_WRITE access right.

lpFileSizeHigh - [out] Pointer to the variable where the high-order word of the file size is returned.  This parameter can be NULL if the application does not require the high-order word.

The return value

If the function succeeds, the return value is the low-order doubleword of the file size, and, if lpFileSizeHigh is non-NULL, the function puts the high-order doubleword of the file size into the variable pointed to by that parameter.

If the function fails and lpFileSizeHigh is NULL, the return value is INVALID_FILE_SIZE.  To get extended error information, call GetLastError().

If the function fails and lpFileSizeHigh is non-NULL, the return value is INVALID_FILE_SIZE and GetLastError() will return a value other than NO_ERROR.

The header file

<windows.h>

 

Table 16:  GetFileSize() information.

#include <windows.h>

#include <stdio.h>

 

int main()

{

// the files' handles

HANDLE hFile, hFile1;

// filenames, change accordingly

char fname[ ] = "c:\\test.doc";

char fname1[ ] = "c:\\txtcodes\\module11.txt";

// temporary storage for file sizes

DWORD dwFileSize;

DWORD dwFileType;

   // create the test file. Open it "Create Always" to overwrite any existing file...

  hFile = CreateFile(fname, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

  if(hFile == INVALID_HANDLE_VALUE)

  {

    printf("hFile is NULL\n");

    printf("Could not create %s\n", fname);

    // return error

    return 4;

  }

// get the file type...

dwFileType = GetFileType(hFile);

// verify that the correct file size was written.

dwFileSize = GetFileSize(hFile, NULL);

printf("%s size is %d bytes and file type is %d\n", fname, dwFileSize, dwFileType);

CloseHandle(hFile);   //close the file handle and the file itself

// opening the existing file

hFile1 = CreateFile(fname1,                      // file to open

                GENERIC_READ,                      // open for reading

                FILE_SHARE_READ,               // share for reading

                NULL,                                          // default security

                OPEN_EXISTING,                     // existing file only

                FILE_ATTRIBUTE_NORMAL,  // normal file

                NULL);                     // no attribute template

 

if(hFile1 == INVALID_HANDLE_VALUE)

{

    printf("Could not open %s file, error %d\n", fname1, GetLastError());

    return 1;

}

dwFileType = GetFileType(hFile1);

dwFileSize = GetFileSize(hFile1, NULL);

printf("%s size is %d bytes and file type is %d\n", fname1, dwFileSize, dwFileType);

// close the file's handle and itself

CloseHandle(hFile1);

return 0;

}

 

The output:

 

c:\test.doc size is 0 bytes and file type is 1

c:\txtcodes\module11.txt size is 10518 bytes and file type is 1

Press any key to continue

The following is the previous example compiled using VC++ Express Edition with SDK on Win XP Pro SP2.

 

#include <windows.h>

#include <stdio.h>

 

int main()

{

    // the files' handles

    HANDLE hFile, hFile1;

    // filenames, change accordingly

    char *fname = "c:\\test.doc";

    char *fname1 = "c:\\myfile.txt";

    // temporary storage for file sizes

    DWORD dwFileSize;

    DWORD dwFileType;

    // create the test file. Open it "Create Always" to overwrite any existing file...

    hFile = CreateFile((LPCWSTR)fname, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

    if(hFile == INVALID_HANDLE_VALUE)

    {

        printf("hFile is NULL\n");

        printf("Could not create %s\n", fname);

        // return error

        return 4;

    }

    // get the file type...

    dwFileType = GetFileType(hFile);

    // verify that the correct file size was written.

    dwFileSize = GetFileSize(hFile, NULL);

    printf("%s size is %d bytes and file type is %d\n", fname, dwFileSize, dwFileType);

    CloseHandle(hFile); //close the file handle and the file itself

    // opening the existing file

    hFile1 = CreateFile((LPCWSTR)fname1, // file to open

        GENERIC_READ, // open for reading

        FILE_SHARE_READ, // share for reading

        NULL, // default security

        OPEN_EXISTING, // existing file only

        FILE_ATTRIBUTE_NORMAL, // normal file

        NULL); // no attribute template

    if(hFile1 == INVALID_HANDLE_VALUE)

    {

        printf("Could not open %s file, error %d\n", fname1, GetLastError());

        return 1;

    }

        dwFileType = GetFileType(hFile1);

        dwFileSize = GetFileSize(hFile1, NULL);

        printf("%s size is %d bytes and file type is %d\n", fname1, dwFileSize, dwFileType);

        // close the file's handle and itself

        CloseHandle(hFile1);

        return 0;

    }

 

    A sample output:

 

 

 

 

 

 

 

 

 

 

 

 

 

Further reading and digging:

 

  1. Check the best selling C, C++ and Windows books at Amazon.com.

  2. Microsoft Visual C++, online MSDN.

  3. For Multibytes, Unicode characters and Localization please refer to Locale, wide characters & Unicode (Story) and Windows users & groups programming tutorials (Implementation).

  4. Windows data type information is in Data types used in Windows programming.

  5. Structure, enum, union and typedef story can be found C/C++ struct, enum, union & typedef.

  6. Notation used in MSDN is Hungarian Notation instead of CamelCase and is discussed VC++ programming notations.

 

 

 

 

 

|< C & Win32 programming 3 | Main | C & Win32 programming 5 >| Site Index | Download |


 

C & C++ Programming Tutorial | C Programming Practice