My Training Period: aa hours. Before you begin, read some instruction here.
The skills that supposed to be acquired:
The Background Story: The Microsoft C Run-time Libraries
|
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.
Figure 0
It also can be accessed by selecting your project directory (in the Solution Explorer pane) → Right click → Select the Properties menu as shown below.
Figure 1
The following Figure is a project Property pages.
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 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 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.
- 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.
- 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);
- 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. |
- What header files need to be included? For example the _chsize needs:
<io.h>
- 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.
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.
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 |
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 |
#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
// for example if no one space: "A:"--> ++mydrives[0];
// you may try char mydrives[ ] = {" A: "}; or char mydrives[ ] = " A: ";
TCHAR 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
|
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 |
#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");
// may need a casting from TCHAR to char * here
// printf((char *)g_szText);
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 sample:
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 |
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 |
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 |
_chdir("c:\\temp");
/*******cruntime.cpp*******/
/***Visual C++ .Net/7.0****/
#include <stdio.h>
#include <conio.h>
#include <direct.h>
#include <stdlib.h>
#include <ctype.h>
int main(void)
{
int chr, drive, curdrive;
static char path[_MAX_PATH];
char buffer[_MAX_PATH];
char newdir[50] = "\\testdir";
// char path1[50] = "C:\\Windows\\System32\\config";
char path1[50] = "C:\\WINNT\\System32\\config";
/* save current drive. */
curdrive = _getdrive();
printf("Available drives in this machine are: \n");
/* if we can switch to the drive, it exists. */
for(drive = 1; drive <= 26; drive++)
if(!_chdrive(drive))
printf("%c: ", drive + 'A' - 1);
printf("\n\nType drive letter to check: ");
chr = _getch();
if(chr == 27)
printf("Illegal drive input\n");
if(isalpha(chr))
_putch(chr);
if(_getdcwd(toupper(chr) - 'A' + 1, path, _MAX_PATH) != NULL)
printf("\nCurrent directory on that drive is:\n%s\n", path);
/* restore original drive. */
_chdrive(curdrive);
/* get the current working directory */
if(_getcwd(buffer, _MAX_PATH) == NULL)
perror("_getcwd error");
else
printf("\nCurrent working directory is: %s\n", buffer);
/* create a directory and then delete */
if(_mkdir(newdir) == 0)
{
printf("\nDirectory %s was successfully created\n", newdir);
system("dir \\testdir");
if(_rmdir("\\testdir") == 0)
printf("\nDirectory %s was successfully removed\n", newdir);
else
printf("\nProblem removing directory %s\n", newdir);
}
else
printf("\nProblem creating directory %s\n", newdir);
/* uses _chdir() function to verify that a given directory exists */
printf("\n");
printf("Change directory........\n");
if(_chdir(path1))
printf("Unable to locate the directory: %s\n", path1);
else
system("dir *.log /a");
printf("\n");
return 0;
}
The output:
Available drives in this machine are:
C: D: F:
Type drive letter to check: c
Current directory on that drive is:
c:\Program Files\Microsoft Visual Studio .NET 2003\Common7\IDE
Current working directory is: D:\mcruntime
Directory \testdir was successfully created
Volume in drive D has no label.
Volume Serial Number is 90C8-54BB
Directory of D:\testdir
05/17/2005 08:54p <DIR> .
05/17/2005 08:54p <DIR> ..
0 File(s) 0 bytes
2 Dir(s) 13,975,789,568 bytes free
Directory \testdir was successfully removed
Change directory........
Volume in drive C has no label.
Volume Serial Number is B03D-C18F
Directory of C:\WINNT\System32\config
05/17/2005 08:07p 1,024 default.LOG
05/17/2005 08:08p 1,024 SAM.LOG
05/17/2005 08:17p 1,024 SECURITY.LOG
05/17/2005 08:54p 12,288 software.LOG
06/05/2004 07:06a 1,024 system.LOG
06/05/2004 07:06a 0 TempKey.LOG
06/05/2004 07:06a 1,024 userdiff.LOG
7 File(s) 17,408 bytes
0 Dir(s) 7,208,861,696 bytes free
Press any key to continue
The following is a sample output run using VC++ EE 2005 on another machine.
The following example tested on Win XP Pro SP2 using Visual C++ Express Edition 2005 with Windows SDK installed.
/*******cruntime.cpp*******/
/***Visual C++ EE 2005 on Win XP Pro SP 2 ****/
#include <stdio.h>
#include <conio.h>
#include <direct.h>
#include <stdlib.h>
#include <ctype.h>
int main(void)
{
int chr, drive, curdrive;
static char path[_MAX_PATH];
char buffer[_MAX_PATH];
char newdir[50] = "\\testdir";
// char path1[50] = "C:\\WINNT\\System32\\config";
char path1[50] = "C:\\Windows\\System32\\config";
/* save current drive. */
curdrive = _getdrive();
printf("Available drives in this machine are: \n");
/* if we can switch to the drive, it exists. */
for(drive = 1; drive <= 26; drive++)
if(!_chdrive(drive))
printf("%c: ", drive + 'A' - 1);
printf("\n\nType drive letter to check: ");
chr = _getch();
if(chr == 27)
printf("Illegal drive input\n");
if(isalpha(chr))
_putch(chr);
if(_getdcwd(toupper(chr) - 'A' + 1, path, _MAX_PATH) != NULL)
printf("\nCurrent directory on that drive is:\n%s\n", path);
/* restore original drive. */
_chdrive(curdrive);
/* get the current working directory */
if(_getcwd(buffer, _MAX_PATH) == NULL)
perror("_getcwd error");
else
printf("\nCurrent working directory is: %s\n", buffer);
/* create a directory and then delete */
if(_mkdir(newdir) == 0)
{
printf("\nDirectory %s was successfully created\n", newdir);
system("dir \\testdir");
if(_rmdir("\\testdir") == 0)
printf("\nDirectory %s was successfully removed\n", newdir);
else
printf("\nProblem removing directory %s\n", newdir);
}
else
printf("\nProblem creating directory %s\n", newdir);
/* uses _chdir() function to verify that a given directory exists */
printf("\n");
printf("Change directory........\n");
if(_chdir(path1))
printf("Unable to locate the directory: %s\n", path1);
else
system("dir *.log /a");
printf("\n");
return 0;
}
A sample output:
For the above mentioned IDEs, you need to set the Character Set to Not Set else you need to change all the types in the programs to Unicode. The following Figures show the project setting for the character set used in the project.
Visual C++ Express Edition 2005
Visual C++ 2005 of the Visual Studio 2005
C & C++ Programming Tutorial | C Programming Practice | Win32 and C with Unicode Version