Core summary of Windows core programming (chapter fourth process (ii)) (2018.6.17)

Source: Internet
Author: User

Learning Goals

In the previous section, we learned about processes, ingress functions, and process instance handles, and there was a wave of testing for a global variable initialization problem before going to the command line of the process to learn. The learning objectives in this section are as follows:
1. Test what global variables the C + + runtime startup function initializes
2. The command line of the process
3. Environment variables for the process
4. Current drive and directory of the process
5. Judging the system version
6. Create a process (CreateProcess function)

Test the startup function to initialize which global variables

We know that the startup function of the C + + runtime will do something to call our entry function afterwards, and the parameters of the entry function are initialized before the call. Then I have a question about what global variables are initialized by the global variables with the entry function (the four entry functions, Main, WMAin, wWinMain, WinMain, respectively). I made the following test:
(1) To test the initialization of global variables for both Unicode and multibyte character sets under the CUI program:

#include <windows.h> #include <tchar.h> #include <iostream>using namespace std;int _tmain (int argc, _    tchar* argv[]) {//Test two times: the first time in a Unicode environment, the second time in a multibyte character set environment, note the difference in output.    Test _environ is initialized to a useful value char** P1 = _environ;            if (p1! = NULL) {while (*P1) {cout << *p1 << Endl;        p1++;    } cout << "---------------------------above is the value of _environ output---------------------------------" << Endl;    }//test _wenviron have been initialized to a useful value wchar_t** P2 = _wenviron;            if (P2! = NULL) {while (*P2) {wcout << *p2 << Endl;        p2++;    } cout << "--------------------------above is the value of _wenviron output--------------------------" << Endl;    }//test __argv have been initialized to a useful value char** p3= __argv;            if (p3! = NULL) {while (*P3) {cout << *p3 << Endl;        p3++; } cout << "-------------------------above is the value of the __ARGV output----------------------------"<< Endl;    }//test __wargv have been initialized to a useful value wchar_t** P4 = __WARGV;            if (P4! = NULL) {while (*P4) {wcout << *p4 << Endl;        p4++;    } cout << "-------------------------above is the value of __wargv output----------------------------" << Endl;    } system ("Pause"); return 0;}

Test results: The output is too long bad, here is only a summary, running results can be run on their own view. If you write the main function is _tmain, then where the _environ and _wenviron global variables, in the Unicode environment, _environ and _wenviron global variables are initialized to a useful value. In the multibyte character set, the _environ global variable is initialized to a useful value, and the _wenviron global variable is null. Obviously, there is a difference in the description of the P69 page table in the book.
(2) To test the initialization of global variables for both Unicode and multibyte character sets under GUI programs:
1. It is clear that the following test results are the same as in the WMAin function test.

2. As you can see, the following test results are the same as in the main function test.

(3) Big summary:
I have questioned the description of the global variable initialization table for P69 pages in the book. If you write the main function is _tmain, then where the _environ and _wenviron global variables, in the Unicode environment, _environ and _wenviron global variables are initialized to a useful value. In the multibyte character set, the _environ global variable is initialized to a useful value, and the _wenviron global variable is null. Simply put, whether or not _unicode is defined, _environ is initialized to a useful value, and _wenviron is influenced by the character set, which creates ambiguity with the book. and wargv and argv are the definition of the book. If you write the main function is _tWinMain, then where the _environ and _wenviron global variables, in the Unicode environment, _environ and _wenviron global variables are initialized to a useful value. In the multibyte character set, the _environ global variable is initialized to a useful value, and the _wenviron global variable is null. and wargv and argv are the definition of the book. Note that if Windows is programmed to use either main or wmain instead of the _tmain and _tWinMain functions, the above summary is not necessarily true, but because of the two character sets, it is recommended that the entry function written later will write _tmain and _tWinMain functions.

The command line of the process

(1) If you are running the Cui application, the global variables (including command line arguments argc, argv, or wargv are already initialized when the C + + runtime starts the function execution. If argc, argv is initialized under the Unicode character set, and argc, __WARGV is initialized under multiple character sets. Then call the entry point function _tmain and pass the parameter argc, argv, or wargv into the _tmain function. The
now tests the parameters of the _tmain function:

  #include <windows.h> #include <tchar.h> #include <iostream>using namespace Std;int _tmain (int argc, _tchar* argv[]) {/* There are two ways to enter command-line arguments: 1. Properties---Configuration properties, debug command parameters: For example: Wo ai ni 2. Open the Command Line window (CMD) in the executable directory, enter the file name + command line arguments: for example: Consolea Pplication9 wo ai ni one thing to note, however, is the character set problem, when the project character set is a Unicode character set, the Wcout output command line is used in C + +.    When the item character set is a multibyte character set, the cout output command line is used in C + +.    Note that regardless of the command-line arguments entered in both ways, global variables argc, __ARGV, __wargv are initialized in the C + + runtime startup function. So the argv parameter passed into the _tmain function is also a string corresponding to the character set encoding.    For example, if the element inside the argv array is a wide string under Unicode, the element inside the argv array is an ANSI string if it is under a multibyte character set. Note the first and second way on the output difference, the first output of the first file name string, this string also includes the path.    The second output has only command-line arguments, because the file name is output even if no command-line arguments are filled in, and the file name is just a symbol of running the program.        */for (int i = 0; i < argc; i++) {//cout only output ANSI characters and strings, you can use Wcout to output wide characters.    Wcout << Argv[i] << Endl;    } system ("Pause"); return 0;}  

(2) If you are running the Cui application, the Windows function GetCommandLine will be called to get the full command line of the process (file name + command line arguments) when the C + + runtime starts the function execution. Where the file name is the absolute path) then the function is started to ignore the name of the executable file, including the path, and then a pointer to the remainder of the command line is passed to the WinMain pszcmdline parameter. The signature of the function is given below:

LPTSTR WINAPI GetCommandLine(void);

Here's an example:

You can see that cmdline contains the absolute path of the file name and command-line arguments. The Pszcmdline parameter has only command-line arguments, because the file name has been ignored in the Startup function processing.
(3) We can also use the COMMANDLINETOARGVW function to decompose the complete command line obtained by the Getcommandlinew function into separate tokens.
The function is prototyped as follows:

LPWSTR* CommandLinetoArgvW(LPCWSTR,int*);参数1是指向一个命令行字符串,通常利用GetCommandLineW获取。参数2是获取命令行实参的个数。返回的字符串数组所使用的内存,用LocalFree来释放!

The following is an example code for MSDN: the use of the COMMANDLINETOARGVW function under the CUI program

#include<windows.h>#include<tchar.h>#include<iostream>using namespace std;int _tmain(int argc, _TCHAR* argv[]){    LPWSTR *szArglist;//用于    int nArgs;    int i;    /*    CommandLineToArgvW函数只有Unicode版本的,所以参数1也必须使用Unicode版本的GetCommandLineW来获取完整的命令行    参数2是存储完整命令行中一共有多少个命令行参数,包括文件名参数。    CommandLineToArgvW函数返回的是一个Unicode字符串指针数组的地址。    这个函数将参数1完整命令行分解成单独的标记。    */    LPTSTR cmdLine;    cmdLine = GetCommandLine();    printf("%ws\n", cmdLine);//这个是输出完整命令行    szArglist = CommandLineToArgvW(GetCommandLineW(), &nArgs);    if (NULL == szArglist)    {        wprintf(L"CommandLineToArgvW failed\n");        return 0;    }    else for (i = 0; i<nArgs; i++) printf("%d: %ws\n", i, szArglist[i]);//这个是输出分解后放到字符串数组中的内容    LocalFree(szArglist);    system("pause");    return 0;}

Under the CUI program, the ARGV function of the entry point function has been decomposed into the command-line arguments, in fact, the function is more useful in GUI programs, such as the use of the following code:

#include<windows.h>#include<tchar.h>int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE, PTSTR pszCmdLine, int nCmdShow){    LPWSTR *szArglist;//用于    int nArgs;    LPTSTR cmdLine;    cmdLine = GetCommandLineW();    szArglist = CommandLineToArgvW(GetCommandLineW(), &nArgs);    LocalFree(szArglist);    return 0;}

The test results are as follows:

Environment variables for processes

In our well-known Windows system, there is always an environment variable. We also know that environment variables can be obtained or set in the environment variables in the advanced system settings in the Windows interface. But in fact, the environment variables are actually stored in the registry, each Windows system Registry Editor is C:\Windows\regedit.exe, we know that under the visual interface (Advanced system settings Open) There are two environment variables, namely system variables and user variables. System variables and user variables are two paths under Registry Editor (System variable path: HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Session manager\environment ; User Variable path: hkey_current_user\environment). Here's a Registry Editor:

Okay, here we are. In fact, each process is created with an environment block associated with it, that is, a chunk of memory allocated within the process address space, and the memory block contains a string that looks like this:

=::=::\ ...VarName1=VarValue1\0VarName2=VarValue2\0VarName3=VarValue3\0VarNameX=VarValueX\0\0

We should note that the VarName1, VarName2, and so on the left of the equals sign are the names of the environment variables, while the VarValue1, VarValue2, and so on the right of the equals sign are the values of the environment variables. One more important point is that the assignment of the environment variable at the end of each row has a ' getenvironmentstrings ', which is a string terminator, which is useful when the next function iterates through the full environment variable string.
There are two ways to get the complete block of the environment, the first way is to call the Getenvironmentstrings function to get the full environment variable (and the GetEnvironmentVariable function gets the value of a single specified environment variable name, The format of the complete environment block, as described above, is given in the following example, and the second method is specific to the Cui program, which is implemented by the TCHAR *envp[] parameter that is received by the Ingress function. Unlike the value returned by Getenvironmentstrings, Getenvironmentstrings returns the complete block of the environment, and ENVP is an array of string pointers, each pointing to a different environment variable whose definition takes the general "name = value" Format), the last element in the array is a null pointer, which means that this is the end of the array, so we can use this null pointer as the end of the traversal, and we need to note that the invalid strings beginning with the equals sign have been removed before we receive the ENVP. So it doesn't have to be handled as long as you get the array elements.
(1) The following is the first example of the use of getenvironmentstrings function:
Let's first put the function signatures of the two functions that will be used.
The 1.GetEnvironmentStrings function is used to get all environment variable strings:

LPTCH WINAPI GetEnvironmentStrings(void);返回值:成功时,返回指向保存环境变量的缓冲区;失败时,返回值为NULL。

The 2.FreeEnvironmentStrings function is used to release the block of memory returned by Getenvironmentstrings:

  BOOL WINAPI freeenvironmentstrings (__in lptch lpszenvironmentblock); return value: When successful, returns a value other than 0, or 0 when failed. You can call GetLastError () to view further error messages. 
  #include <windows.h> #include <tchar.h> #include <stdio.h> #include <strsafe.h>int    _tmain () {LPTSTR lpszvariable;    Lptch Lpvenv;//lptch is WCHAR * data type, pointer variable size_t itarget that points to wide characters;    Call the Getenvironmentstrings function to get the complete memory block of the environment variable and let lpvenv point to this memory block lpvenv = Getenvironmentstrings (); If the obtained environment block is empty, the function call fails and gets the error code if (lpvenv = = NULL) {_tprintf (TEXT ("Getenvironmentstrings failed (%d) \ n"), Getl        Asterror ());    return 0; The environment variable string that//lpvenv points to is delimited by a null, which is the ' \ S ' partition, and you can go back to the approximate format of the environment string I showed earlier.    And the string ends with a null-terminated lpszvariable = (LPTSTR) lpvenv;        while (*lpszvariable) {_tprintf (TEXT ("%s\n"), lpszvariable); Stringcchlength (lpszvariable, &itarget);//path's value is too long, I set 1000 for the maximum allowable number of characters lpszvariable + = ITarget + 1;//Move pointer, access the next    The value of the environment variable}//If the memory block returned by the Getenvironmentstrings function is not used, remember to release freeenvironmentstrings (LPVENV);    System ("pause"); return 1;}  

The results of the operation are as follows:

(2) Here is the use case for the GetEnvironmentVariable function:
Here first put the GetEnvironmentVariable function signature.
The 1.GetEnvironmentVariable function is used to get the specified environment variable:

DWORD WINAPI GetEnvironmentVariable(  __in_opt   LPCTSTR lpName, //环境变量名  __out_opt  LPTSTR lpBuffer, //指向保存环境变量值的缓冲区  __in       DWORD nSize //缓冲区大小(字符数));返回值:成功时,返回真实的环境变量值大小,不包括null结束符;如果lpBuffer大小不足,则返回值是实际所需的字符数大小,lpBuffer内容就未被赋值;失败时,返回0;如果指定的环境变量找不到,GetLastError()返回ERROR_ENVVAR_NOT_FOUND。
#include <windows.h>#include <tchar.h>#include <stdio.h>#include<strsafe.h>int _tmain(){    TCHAR szBuffer[1000];    DWORD dwResult = GetEnvironmentVariable(TEXT("PATH"), szBuffer, 1000);    if (dwResult != 0)    {        _tprintf(TEXT("PATH=%s"), szBuffer);    }    else    {        _tprintf(TEXT("function call falid!"));    }    system("pause");    return 1;}

The results of the operation are as follows:

(2) Here is the use case for the setenvironmentvariable function:
Here first put on the Setenvironmentvariable function signature, later use case has a few attention points need attention.
The 1.SetEnvironmentVariable function is used to set the specified environment variable:

BOOL WINAPI SetEnvironmentVariable(  __in      LPCTSTR lpName, //环境变量名,当该值不存在且lpValue不为NULL时,将创建一个新的环境变量  __in_opt  LPCTSTR lpValue //环境变量值);返回值:成功时,返回非零值;失败时,返回零值,调用GetLastError()查看具体的错误信息。该函数对系统环境变量以及其他进程的环境变量不起作用!

Before writing the test program, I'll add a custom environment variable, mypath, to the user variable, environment variable, high-level system settings, such as My Computer, properties, and the environment variable value is Woaini. Uh... The value is not the focus, probably long below.

Well, the preparation is done, now the focus is to close vs, re-open vs and run the test code (think about why, if not reopen vs will be what the phenomenon, after the note Point has explained the reason for re-opening vs), now put the test code:

  #include <windows.h> #include <tchar.h> #include <stdio.h>int _tmain (int argc,tchar *argv [],tchar *envp[]) {TCHAR szbuffer[1000];//used to store the value of the obtained environment variable DWORD DWRESULT1 = GetEnvironmentVariable (TEXT ("MyPath"), SzB    Uffer, 1000);//First get the value of the MYPATH environment variable that we have set up before, if it should be woaini, but if you do not get it in the test, the function returns 0, then look at the following I said the attention point OH.    if (dwResult1! = 0) {_tprintf (TEXT ("mypath=%s\n"), szbuffer);    } else {_tprintf (TEXT ("function call falid!\n")); } setenvironmentvariable (Text ("MyPath"), Text ("I Love You"));//Here is a new MyPath environment variable for me to re-modify the value of I love you, notice, in fact, this is just modifying the current process of the environment block,  Without affecting the system or user's environment block DWORD DWRESULT2 = getenvironmentvariable (TEXT ("MyPath"), Szbuffer, 1000);//Retrieve the values of the following modified MyPath environment variables here if    (DWRESULT2! = 0)    {_tprintf (TEXT ("mypath=%s\n"), szbuffer);    } else {_tprintf (TEXT ("function call falid!\n"));    } system ("Pause"); return 0;}  

If the steps are correct, the result is the following:

OK, the following points are available:
1. Why do you want to re-open VS, getenvironmentvariable function to get the previously created environment variable MyPath? This is because we've talked about each process being assigned an environment block when it was created, and this environment block is given by the Windows system, so we can guess When running VS, we have already stored the content of the environment block we are going to allocate, and we are the new environment variable mypath after the VS run, then the VS saved piece hasn't been updated yet, so the function is not available, we can only re-open vs. This is just my guess, is to better understand the getenvironmentvariable function, if there are other views, you can leave a message to explore OH. The
2.GetEnvironmentVariable function has no effect on the environment variables of the system environment variables and other processes because a process has been created and the environment blocks have been allocated for the process, and we have added the GetEnvironmentVariable function, Modify or delete the environment block content, and just add, modify, or delete the environment block for the process, not the Windows system or user's environment block.

(3) The following is the use case for the CUI program entry function TCHAR *envp[] parameter:
Here you do not write your own code, directly put on the book P76 page of the sample code (modified).

  #include <windows.h> #include <tchar.h> #include <stdio.h>int _tmain (int argc,tchar *argv [],tchar *envp[]) {int current = 0;//for environment variable count ptstr *pelement = (PTSTR *) envp;//Create a new pointer to the ENVP array of the CUI program Ptstr Pcurre        NT = null;//is used to traverse the pointer of the ENVP array element while (pelement! = NULL) {//takes the element of the array pcurrent = (PTSTR) (*pelement);        As I said earlier, the end of the array is a null pointer, so when you iterate to null it will pelement null and then jump out of the loop if (pcurrent = = null) {pelement = null;            } else {//print traversal to the environment variable _tprintf ("[%u]%s\r\n"), current, pcurrent);    current++;//Count +1 pelement++;//point to the next array element}} system ("Pause"); return 0;}  

The results of the operation are as follows:

(4) Here is the use case for the ExpandEnvironmentStrings function:
Through the previous registry, we can carefully find that some of the environment variable value contains two percent sign (%) between the string, this string is called the replaceable string , as the name implies, we can be replaced by the function ExpandEnvironmentStrings function A replaceable string . You can also find that this replaceable string is visible only in the registry, and environment variables, such as the Advanced system settings, properties, such as My computer, or other ways to get the entire complete environment variable, are not visible in the form of replaceable strings . Next, I'll put the function signature of the Expandenvirnmentstrings function:

DWORD WINAPI ExpandEnvironmentStrings(  _In_      LPCTSTR lpSrc,  _Out_opt_ LPTSTR  lpDst,  _In_      DWORD   nSize);参数1:一个包含可替换字符串的字符串地址(也叫扩展字符串),例如:TEXT("PATH=%PATH%")参数2:用于接收扩展字符串的一个缓冲区的地址参数3:这个缓冲区的最大大小,用字符数来表示。返回值:保存扩展字符串所需的缓冲区的大小,用字符数表示,若参数3小于这个返回值,%%变量就不会扩展,而是被替换为空字符串,所以一般要调用两次ExpandEnvironmentStrings函数。
#include <windows.h>#include <tchar.h>#include <stdio.h>int _tmain(int argc,TCHAR *argv[],TCHAR *envp[]){    //第一次调用ExpandEnvironmentStrings是为了获取保存扩展字符串所需的缓冲区大小,所以函数参数2可以为NULL,参数3为0    DWORD chValue = ExpandEnvironmentStrings(TEXT("USERPROFILE=‘%USERPROFILE%‘"), NULL, 0);    PTSTR pszBuffer = new TCHAR[chValue];//动态创建chValue大小的缓冲区,最后记得释放掉动态创建的空间    chValue = ExpandEnvironmentStrings(TEXT("USERPROFILE=‘%USERPROFILE%‘"), pszBuffer, chValue);//这次调用才是真正获取替换后的字符串    _tprintf(TEXT("%s\r\n%d"), pszBuffer,chValue);//打印扩展字符串的缓冲区和字符数目    delete[]pszBuffer;//释放动态创建的空间    system("pause");    return 0;}

The results of the operation are as follows:

Current drive and directory of the process

Some Windows function calls need to provide a path, for example: The CreateFile function opens a file (without specifying a full pathname, only one file name), then the function looks for files and directories in the current directory of the current drive (for example, C, D, E disks). The system keeps track of the current drive and directory of a process, and we can get the current drive and directory of the process, as well as modify the current drive and directory of the process.
The following is a function signature that gets and sets the current drive and directory, respectively:
1.GetCurrentDirectory function Gets the current directory of the process:

DWORD WINAPI GetCurrentDirectory(  _In_  DWORD  nBufferLength,  _Out_ LPTSTR lpBuffer);nBufferLength:lpBuffer指针指向内存块的大小(单位TCHAR);lpBuffer:接收当前路径的内存块。

2.SetCurrentDirectory function Set Process current directory

BOOL WINAPI SetCurrentDirectory(  _In_ LPCTSTR lpPathName);lpPathName:需要被设置的目录路径

The 3.GetFullPathName function gets the current path of the specified file:

DWORD WINAPI GetFullPathName(  __in   LPCTSTR lpFileName,  __in   DWORD nBufferLength,  __out  LPTSTR lpBuffer,  __out  LPTSTR *lpFilePart);lpFileName:文件名nBufferLength:获取全路径的内存大小(TCHAR)lpBuffer:内存指针lpFilePart:文件名最后一个元素,在lpBuffer中的位置。注意:这个函数,只是将当前路径,粘贴到你给的文件上,其他什么也没有做。

Below, I give use cases to understand the use of these functions:

  #include <windows.h> #include <tchar.h> #include <stdio.h>int _tmain (int argc,tchar *argv    [],tchar *envp[]) {TCHAR Szpath[max_path];    GetCurrentDirectory (MAX_PATH, szpath);//Gets the process current path _tprintf (L "%s\n", szpath);   TCHAR *str = L "d:\\360downloads\\";//Set the current path SetCurrentDirectory (str);    Sets the current path of the file, if the specified str parameter exists in the computer on this path, then the setting is successful, otherwise the setting is invalid, or the previous valid current process directory GetCurrentDirectory (MAX_PATH, szpath);    _tprintf (L "%s\n", szpath);   TCHAR *str1 = L "d:\\ddsdf\\";//The current path of the set SetCurrentDirectory (STR1);    Sets the current path of the file, if the specified str parameter exists in the computer on this path, then the setting is successful, otherwise the setting is invalid, or the previous valid current process directory GetCurrentDirectory (MAX_PATH, szpath); _tprintf (L "%s\n", szpath);//Because the "d:\\ddsdf\\" path does not exist on my computer, the SetCurrentDirectory function setting fails Getfullpathname (l "Wxf1", Max_    PATH, szpath, NULL);    This function simply pastes the current path of the process (szpath) onto the file name (WXF1) you gave, and nothing else is done, check _tprintf (L "%s\n", szpath);    System ("pause"); return 0;}  

The results of the operation are as follows:

Through the above tests, we can draw the following points:
1.GetCurrentDirectory function is to get the current directory of the process, and the function parameter 1 is generally used MAX_PATH (macro definition of 260) is very safe, because this is the directory name or file name is the largest number of characters.
The 2.SetCurrentDirectory function sets the current directory of the process, and if the path specified by the function parameter does not exist on this computer, the setting is invalid or the previous valid current process directory is used.
The 3.GetFullPathName function simply pastes the current path of the process (szpath) onto the file name (WXF1) you gave, and nothing else is done, not checked.
4. In order to better understand the function of the GetCurrentDirectory function to get the current directory of the process, you can put the above code generated executable file to the desktop, and then run, then the process of the current directory is changed

Judging the system version

...... Tomorrow add

Core summary of Windows core programming (chapter fourth process (ii)) (2018.6.17)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.