|< C Storage Class & Memory Functions | Main | C Run-Time 2 >| Site Index | Download |


 

MODULE A

IMPLEMENTATION SPECIFIC

MICROSOFT C Run-Time 1

 

My Training Period:      hours

 

Note:

Program examples compiled using Visual C++ .Net (Visual studio .Net 2003).  It is low-level programming and the .Net used is Unmanaged (/clr is not set: Project menu → your_project_name Properties… sub menu → Configuration Properties folder → General subfolder → Used Managed Extension setting set to No).  All programs are in debug mode, run on Windows 2000 and Xp Pro.

 

 

 

 

Abilities

 

         Able to recognize the standard and implementation specific C.

         Able to grasp the fundamental of the Windows file system, file and directory.

         Able to find and collect the needed information in order to use functions to accomplish your tasks.

         Able to understand and use functions that available in the libraries in your own programs.

 

-      In this Module you will be introduced to the absolute implementation specific of the C/C++, the Microsoft C/C++.  However it is still non-GUI type of programs :o).

-      This brings you to the specific use of the compilers that compile the Windows applications and the programs developed are specific to be run on the Windows platform although in the discussion and program examples of this Module and later on, the standard and non standard (Microsoft extension) libraries will be used together.

-      Make sure you have already fluent in functions because we will learn how to use them.  Remember all the thing about a function such as parameters, return values etc.  The final purpose of this Module and that follows actually to show you how to find and collect all the required information from tons of the documentations to suit your needs in developing programs.

-      Keep in mind that, normally, in libraries we have the following things which defined in and accessed through the header files:

 

       Macro definitions.

       Function prototypes.

       Structure definitions (struct).

       Enumeration definitions (enum).

       Data type definitions.

       The typedef usage.

 

-      For the data type and structure definitions, you will find that use of struct, typedef and enum is normal here and also for Win32 programming (will be discussed in another Module).

-      To better understand you must be fluent on those things.  If you encounter any problem, you might have to go back to basic :o) by referring to Tutorial #1 tenouk.com.

-      Other pre requirement topics include array and pointer.

 

The Background Story: The Microsoft C Run-time Libraries

 

-      The following table lists a various .lib files that comprise the C run-time (CRT) libraries as well as their associated compiler options and preprocessor directives.  The libraries contain the C run-time library functions.

-      For these libraries, the header files used in the programs must have the .h extension.

 

Pure C run-time library

Characteristics

Compiler Option

Preprocessor directives

LIBC.LIB

Single-threaded, static link.

/ML

 

LIBCMT.LIB

Multithreaded, static link.

/MT

_MT

MSVCRT.LIB

Multithreaded, dynamic link (import library for MSVCR70.DLL).  Be aware that if you use the Standard C++ Library, your program will need MSVCP70.DLL to run.

/MD

_MT, _DLL

LIBCD.LIB

Single-threaded, static link (debug).

/MLd

_DEBUG

LIBCMTD.LIB

Multithreaded, static link (debug).

/MTd

_DEBUG, _MT

MSVCRTD.LIB

Multithreaded, dynamic link (import library for MSVCR70D.DLL) (debug)

/MDd

_DEBUG, _MT, _DLL

 

Table 1: C run-time libraries

 

-      The Compiler Options, Preprocessor Directives and other configuration settings can be accessed from Project menu → your_project_name Properties... sub menu.

-      It also can be accessed by selecting your project directory (in the Solution Explorer pane) → Right click → Select the Properties menu as shown below.

 

Visual C++ .Net project settings

 

Figure 1

 

-      The following Figure is a project Property pages.

 

Visual C++ .Net project property settings page

 

Figure 2.

 

-      If you link your program from the command line without a compiler option that specifies a C run-time library, the linker will use LIBC.LIB by default.

-      To build a debug version of your application, the _DEBUG flag must be defined and the application must be linked with a debug version of one of these libraries.

-      However in this Module and that follows we will compile and link by using the Visual C++ .Net IDEs’ menus instead of command line :o).

 

The Standard C++ Library

 

-      The run-time libraries also include .lib files that contain the iostream library and the Standard C++ Library. You should never have to explicitly link to one of these .lib files; the header files in each library link in the correct .lib file.

-      The programs that use this old iostream library will need the .h extension for the header files.

-      Before Visual C++ 4.2, the C run-time libraries contained the iostream library functions.  In Visual C++ 4.2 and later, the old iostream library functions have been removed from LIBC.LIB, LIBCD.LIB, LIBCMT.LIB, LIBCMTD.LIB, MSVCRT.LIB, and MSVCRTD.LIB.

-      This change was made because the Standard C++ Library has been added to Visual C++, and it contains a new set of iostream libraries.

-      Thus, two sets of iostream functions are now included in Visual C++.  The old iostream functions now exist in their own libraries as shown in the following Table.

 

Old iostream library

Characteristics

Compiler Option

Preprocessor directives

LIBCI.LIB

Single-threaded, static link.

/ML

 

LIBCIMT.LIB

Multithreaded, static link.

/MT

_MT

MSVCIRT.LIB

Multithreaded, dynamic link (import library for MSVCI70.DLL).

/MD

_MT, _DLL

LIBCID.LIB

Single threaded, static link.

/MLd

_DEBUG

LIBCIMTD.LIB

Multithreaded, static link.

/MTd

_DEBUG, _MT

MSVCIRTD.LIB

Multithreaded, dynamic link (import library for MSVCI70D.DLL).

/MDd

_DEBUG, _MT, _DLL

 

Table 2: Old iostream libraries

 

-      The new iostream functions, as well as many other new functions, that exist in the Standard C++ Library are shown in the following Table.

-      The programs that use this new iostream library will need the header files without the .h extension such as <string>.

 

Standard C++ Library

Characteristics

Compiler Option

Preprocessor directives

LIBCP.LIB

Single-threaded, static link

/ML

 

LIBCPMT.LIB

Multithreaded, static link

/MT

_MT

MSVCPRT.LIB

Multithreaded, dynamic link (import library for MSVCP70.dll)

/MD

_MT, _DLL

LIBCPD.LIB

Single-threaded, static link

/MLd

_DEBUG

LIBCPMTD.LIB

Multithreaded, static link

/MTd

_DEBUG, _MT

MSVCPRTD.LIB

Multithreaded, dynamic link (import library for MSVCP70.DLL)

/MDd

_DEBUG, _MT, _DLL

 

Table 3: Standard C++ libraries

 

-      The Standard C++ Library and the old iostream library are incompatible, that is they cannot be mixed and only one of them can be linked with your project.

-      The old iostream library created when the standard is not matured yet.

-      When you build a release version of your project, one of the basic C run-time libraries (LIBC.LIB, LIBCMT.LIB, and MSVCRT.LIB) is linked by default, depending on the compiler option you choose (single-threaded, multithreaded, or DLL).

-      Depending on the headers you use in your code, a library from the Standard C++ libraries or one from the old iostream libraries may also be linked, for example:

 

       If you include a Standard C++ Library header in your code, a Standard C++ Library will be linked in automatically by Visual C++ at compile time. For example:

 

#include <ios>

 

       If you include an old iostream library header, an old iostream library will be linked in automatically by Visual C++ at compile time. For example:

 

#include <ios.h>

 

-      Headers determine whether a Standard C++ library, an old iostream library, or neither will be linked.  Compiler options determine which of the libraries to be linked is the default (single-threaded, multithreaded, or DLL).

-      When a specific library compiler option is defined, that library is considered to be the default and its preprocessor directives are automatically defined.  Also read Module 23 for the big picture.

-      As a conclusion, for typical C and C++ programs, by providing the proper header files just let the compiler determine for you which libraries are appropriate to be linked in.

 

The Run-Time Functions

 

-      The following sections will dive more detail some of the functions available in the C run-time library. 

-      These functions used to create routines that can be used to automate many tasks in Windows that not available in the standard C/C++.

-      We will start with category, then the functions available in that category and finally followed by program examples that use some of the functions.

-      The functions discussed here mostly deal with directories and files.

-      For complete information please refer to Microsoft Visual C++ documentation (online MSDN: Microsoft Visual C++).  As a remainder, the following are the things that must be fully understood when you want to use a function, and here, _chsize() is used as an example.

 

1.        What is the use of the function?  This will match with "what are you going to do or create?"  Keep in mind that to accomplish some of the tasks you might need more (several) than one function.  For example:

 

_chsize() used to change the file size.

 

2.        What is the function prototype, so we know how to write (call) a proper syntax of the function.  For example:

 

int _chsize(int handle, long size);

 

3.        From the function prototype, how many parameters, the order and what are their types, so we can create the needed variables.  For example:

 

handle

Handle referring to open file.

size

New length of file in bytes.

 

4.        What header files need to be included?  For example the _chsize needs:

 

<io.h>

 

5.        What is the return type and value?  For example:

 

_chsize returns 0 if the file size is successfully changed.  A return value of –1 indicates an error: errno is set to EACCES if the specified file is locked against access, to EBADF if the specified file is read-only or the handle is invalid, or to ENOSPC if no space is left on the device.

 

-      Hence, you are ready to use the function in any of your programs.  If you still blur about functions, please read C & C++ Functions tutorial.  Not all the needed information is provided here and for complete one, please refers to the Microsoft Visual C++/MSDN/SDK Platform documentations or HERE.

-      For C++, together with the classes, it is used when you develop programs using Microsoft Foundation Class (MFC) and Automatic Template Library (ATL).

-      The notation convention used for identifiers in MSDN documentation is Hungarian Notation and is discussed C/C++ Notations.

 

--------------------The Story and Program Examples---------------------

 

 

Directory Management

 

-      Functions available in this category used to access, modify, and obtain information about the directory structure and are listed in the following Table.

-      Notice that most of the function names are similar to the standard C wherever available, except prefixed with underscore ( _ ) :o).  The functions available in this category are listed in the following Table.

 

Directory Management Functions

 

-      The following Table lists functions used for directory control and management.

 

Function

Use

_chdir(), _wchdir()

Change current working directory.

_chdrive()

Change current drive.

_getcwd(), _wgetcwd()

Get current working directory for default drive.

_getdcwd(), _wgetdcwd()

Get current working directory for specified drive.

_getdiskfree()

Populates a _diskfree_t structure with information about a disk drive.

_getdrive()

Get current (default) drive.

_getdrives()

Returns a bitmask representing the currently available disk drives.

_mkdir(), _wmkdir()

Make new directory.

_rmdir(), _wrmdir()

Remove directory.

_searchenv(), _wsearchenv()

Search for given file on specified paths.

 

Table 4:  Directory control functions

 

-      The following is an example of the needed information in order to use the  _getdrives() function.

 

Information

Description

The function

_getdrives().

The use

Returns a bitmask representing the currently available disk drives.

The prototype

int _getdrives(void);

Example

ULONG DriveMask = _getdrives();

 

while (DriveMask)

{ //List all the drives...

  if(DriveMask & 1)

    printf(mydrives);

    ++mydrives[1];

    //Shift the bit masks binary

    //to the right and repeat

    DriveMask >>= 1;

}

The parameters

void

The return value

If the function succeeds, the return value is a bitmask representing the currently available disk drives. Bit position 0 (the least-significant bit) is drive A, bit position 1 is drive B, bit position 2 is drive C, and so on. If the function fails, the return value is zero. To get extended error information, call GetLastError().

The header file

<direct.h>

 

Table 5:  _getdrives() information

 

-      The following program example uses the _getdrives() function to list the available logical drives in the current machine.

 

#include <windows.h>

#include <direct.h>

#include <stdio.h>

#include <tchar.h>

 

//Buffer, be careful with terminated NULL

//Must match with ++mydrives[1]...that is one space

//Example if no one space: "A:"--> ++mydrives[0];

TCHAR mydrives[] = " A: ";

//Or char mydrives[] = {" A: "};

//Or char mydrives[] = " A: ";

 

int main()

{

   //Get the drives bit masks...1 is available, 0 is not available

   //A = least significant bit...

   ULONG DriveMask = _getdrives();

   //If something wrong

   if(DriveMask == 0)

      printf("_getdrives() failed with failure code: %d\n", GetLastError());

   else

   {

     printf("This machine has the following logical drives:\n");

     while (DriveMask)

  {      //List all the drives...

         if(DriveMask & 1)

            printf(mydrives);

         //Go to the next drive strings with one space

         ++mydrives[1];

         //Shift the bit masks binary

         //to the right and repeat

         DriveMask >>= 1;

      }

  printf("\n");

   }

   return 0;

}

 

The output:

 

This machine has the following logical drives:

 A:  C:  D:  E:  F:  G:  H:  I:  J:  K:  L:

Press any key to continue

 

-      The following is an example of the needed information in order to use the  _getdiskfree() function.

 

Information

Description

The function

_getdiskfree().

The use

Populates a _diskfree_t structure with information about a disk drive.

The prototype

unsigned _getdiskfree(
   unsigned drive,
   struct _diskfree_t * driveinfo);

Example

struct _diskfree_t df = {0};

unsigned uDrive;

_getdiskfree(uDrive, &df);

The parameters

drive - The disk drive for which you want information.

driveinfo - A _diskfree_t structure that will be populated with information about the drive.  _diskfree_t is defined in direct.h.

The return value

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

The header file

<direct.h>

 

Table 6:  _getdiskfree() information

 

-      The following program example uses the _getdiskfree() function to list logical drives information in the current machine.

 

#include <windows.h>

#include <direct.h>

#include <stdio.h>

#include <tchar.h>

 

TCHAR g_szText[]  = _T("Drive Total_clus Available_clus Sec/Cluster Bytes/Sec\n");

TCHAR g_szText1[] = _T("----- ---------- -------------- ----------- ---------\n");

TCHAR g_szInfo[]  = _T("->                                                   \n");

 

//For data display format...

//Right justified, thousand comma separated and other format

//for displayed data

void utoiRightJustified(TCHAR* szLeft, TCHAR* szRight, unsigned uValue)

{

   TCHAR* szCur = szRight;

   int nComma = 0;

 

   if(uValue)

   {

      while(uValue && (szCur >= szLeft))

         {

         if(nComma == 3)

               {

            *szCur = ',';

            nComma = 0;

         }

         else

               {

            *szCur = (uValue % 10) | 0x30;

            uValue /= 10;

            ++nComma;

         }

         --szCur;

      }

   }

   else

   {

      *szCur = '0';

      --szCur;

   }

 

   if(uValue)

   {

      szCur = szLeft;

      while(szCur <= szRight)

         {//If not enough field to display the data...

         *szCur = '*';

         ++szCur;

      }

   }

}

 

int main()

{

   TCHAR szMsg[4200];

   struct _diskfree_t df = {0};

   //Search drives and assigns the bit masks to

   //uDriveMask variable...

   ULONG uDriveMask = _getdrives();

   unsigned uErr, uLen, uDrive;

  

   printf("clus - cluster, sec - sector\n");

   printf(g_szText);

   printf(g_szText1);

 

   for(uDrive = 1; uDrive <= 26; ++uDrive)

   {

      //If the drive is available...

      if(uDriveMask & 1)

         { //Call _getdiskfree()...

         uErr = _getdiskfree(uDrive, &df);

         //Provide some storage

         memcpy(szMsg, g_szInfo, sizeof(g_szInfo));

         szMsg[3] = uDrive + 'A' - 1;

        

         //If _getdiskfree() is no error, display the data

         if(uErr == 0)

               {

            utoiRightJustified(szMsg+4, szMsg+15, df.total_clusters);

            utoiRightJustified(szMsg+18, szMsg+29, df.avail_clusters);

            utoiRightJustified(szMsg+27, szMsg+37, df.sectors_per_cluster);

            utoiRightJustified(szMsg+40, szMsg+50, df.bytes_per_sector);

         }

         else

           {//Print system message and left other fields empty

            uLen = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, uErr, 0, szMsg+8, 4100, NULL);

            szMsg[uLen+6] = ' ';

            szMsg[uLen+7] = ' ';

            szMsg[uLen+8] = ' ';

         }

         printf(szMsg);

      }

      //shift right the found drive bit masks and

      //repeat the process

      uDriveMask >>= 1;

   }

   return 0;

}

 

The output:

 

clus - cluster, sec - sector

Drive Total_clus Available_clus Sec/Cluster Bytes/Sec

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

-> A       2,847           834       1          512

-> C   2,560,351        62,315       8          512

-> D   2,560,351     1,615,299       8          512

-> E   2,560,351     2,310,975       8          512

-> F   2,560,351     2,054,239       8          512

-> G   2,353,514     2,039,396       8          512

-> H   2,560,351     2,394,177       8          512

-> I   2,381,628     1,618,063       8          512

-> J     321,935             0       1        2,048

-> L      63,419        20,706      16          512

Press any key to continue

 

-      Note that J: is CD-RW, L: is thumb drive and A: is a floppy.  For floppy and CD-ROM, you have to insert the media.

-      The following is an example of the needed information in order to use the  _getdrive() function.

 

Information

Description

The function

_getdrive().

The use

Gets the current disk drive.

The prototype

int _getdrive(void);

Example

int curdrive;

curdrive = _getdrive();

The parameters

void

The return value

Returns the current (default) drive (1=A, 2=B, and so on).  There is no error return.

The header file

<direct.h>

 

Table 7:  _getdrive() information

 

-      The following Table lists the needed information in order to use the _chdir(), _wchdir() functions.

 

Information

Description

The function

_chdir(), _wchdir().

The use

Change the current working directory.

The prototype

int _chdir(const char *dirname);

/*For wide character*/

int _wchdir(const wchar_t *dirname);

Example

char path1[50] = "C:\\WINNT\\System32\\config";

_chdir(path1);

The parameters

dirname - Path of new working directory.

The return value

These functions return a value of 0 if successful.  A return value of –1 indicates that the specified path could not be found, in which case errno is set to ENOENT.

The header file

<direct.h> or <wchar.h> for _wchdir().

 

Table 8:  _chdir(), _wchdir() functions information

 

-      The _chdir() function changes the current working directory to the directory specified by dirname.  The dirname parameter must refer to an existing directory.

-      This function can change the current working directory on any drive.  If a new drive letter is specified in dirname, the default drive letter will be changed as well.

-      For example, if A is the default drive letter and \BIN is the current working directory, the following call changes the current working directory for drive C and establishes C as the new default drive:

 

_chdir("c:\\te