socket通信

  CreatePipe 

VB声明 
Declare Function CreatePipe Lib "kernel32" Alias "CreatePipe" (phReadPipe As Long, phWritePipe As Long, lpPipeAttributes As SECURITY_ATTRIBUTES, ByVal nSize As Long) As Long 
说明 
创建一个匿名管道 
返回值 
Long,非零表示成功,零表示失败。会设置GetLastError 
参数表 
参数 类型及说明 
phReadPipe Long,指定一个 变量 ,设为管道读入(输出)端的一个句柄 
phWritePipe Long,指定一个变量,设为管道写入(输入)端的一个句柄 

lpPipeAttributes SECURITY_ATTRIBUTES,指定一个SECURITY_ATTRIBUTES结构,或者传递零值(将参数声明为ByVal As Long,并传递零值),以便使用不允许继承的一个默认描述符 


typedef struct _SECURITY_ATTRIBUTES { 
DWORD nLength; //结构体大小,可用sizeof取得
LPVOID lpSecurityDescriptor; //安全描述符
BOOL bInheritHandle;//安全描述的对象能否被新创建的进程继承
} SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES;


nSize Long,管道缓冲区的建议大小。零表示用默认值 
注解 

匿名管道不允许异步操作,所以如在一个管道中写入数据,且缓冲区已满,那么除非另一个进程从管道中读出数据,从而腾出了缓冲区的空间,否则写入函数不会返回


createthread 


Windows API函数。该函数在主线程的基础上创建一个新线程。微软在Windows API中提供了建立新的线程的函数CreateThread。

概述

当使用CreateProcess调用时,系统将创建一个进程和一个主线程。CreateThread将在主线程的基础上创建一个新线程,大致做如下步骤:

1.在内核对象中分配一个线程标识/句柄,可供管理,由CreateThread返回

2.把线程退出码置为STILL_ACTIVE,把线程挂起计数置1

3.分配context结构

4.分配两页的物理存储以准备栈,保护页设置为PAGE_READWRITE,第2页设为PAGE_GUARD

5.lpStartAddr和lpvThread值被放在栈顶,使它们成为传送给StartOfThread的参数

6.把context结构的栈指针指向栈顶(第5步)指令指针指向startOfThread函数

MSDN中CreateThread原型:

HANDLE CreateThread(

LPSECURITY_ATTRIBUTES lpThreadAttributes, // SD

SIZE_T dwStackSize, // initial stack size

LPTHREAD_START_ROUTINE lpStartAddress, // thread function

LPVOID lpParameter, // thread argument

DWORD dwCreationFlags, // creation option

LPDWORD lpThreadId // thread identifier

);

lpThreadAttributes:指向SECURITY_ATTRIBUTES型态的结构的指针。在Windows 98中忽略该参数。在Windows NT中,NULL使用默认安全性,不可以被子线程继承,否则需要定义一个结构体将它的bInheritHandle成员初始化为TRUE

dwStackSize,设置初始栈的大小,以字节为单位,如果为0,那么默认将使用与调用该函数的线程相同的栈空间大小。任何情况下,Windows根据需要动态延长堆栈的大小。

lpStartAddress,指向线程函数的指针,形式:@函数名,函数名称没有限制,但是必须以下列形式声明:

DWORD WINAPI ThreadProc (LPVOID lpParam) ,格式不正确将无法调用成功。

//也可以直接调用void类型

//但lpStartAddress要这样通过LPTHREAD_START_ROUTINE转换如:(LPTHREAD_START_ROUTINE)MyVoid

//然后在线程声明为:

void MyVoid()

{

return;

}

lpParameter:向线程函数传递的参数,是一个指向结构的指针,不需传递参数时,为NULL。

dwCreationFlags :线程标志,可取值如下

(1)CREATE_SUSPENDED(0x00000004):创建一个挂起的线程,

(2)0:表示创建后立即激活。

(3)STACK_SIZE_PARAM_IS_A_RESERVATION(0x00010000):dwStackSize参数指定初始的保留堆栈的大小,否则,dwStackSize指定提交的大小。该标记值在Windows 2000/NT and Windows Me/98/95上不支持。

lpThreadId:保存新线程的id。

返回值:

函数成功,返回线程句柄;函数失败返回false。

若不想返回线程ID,设置值为NULL。

函数说明:

创建一个线程。

语法:

hThread = CreateThread (&security_attributes, dwStackSize, ThreadProc,pParam, dwFlags, &idThread) ;

一般并不推荐使用 CreateThread函数,而推荐使用RTL库里的System单元中定义的 BeginThread函数,因为这除了能创建一个线程和一个入口函数以外,还增加了几项保护措施。

在MFC程序中,应该调用AfxBeginThread函数,在Visual C++程序中应调用_beginthreadex函数。

编辑本段内存泄漏

在很多参考书上,都说不要用CreateThread 创建线程、并用CloseHandle来关闭这个线程,因为这样做会导致内存泄漏,而应该用_beginthread来创建线程,_endthread来销毁线程。其实,真正的原因并非如此。看如下一段代码:

HANDLE CreateThread(

LPSECURITY_ATTRIBUTES lpThreadAttributes, //线程安全属性

DWORD dwStackSize, // 堆栈大小

LPTHREAD_START_ROUTINE lpStartAddress, // 线程函数

LPVOID lpParameter, //线程参数

DWORD dwCreationFlags, // 线程创建属性

LPDWORD lpThreadId // 线程ID

);

线程中止运行后,线程对象仍然在系统中,必须通过CloseHandle函数来关闭该线程对象。CloseHandle函数的原型是:

BOOL CloseHandle( HANDLE hObject );//HANDLE hObject 对象句柄

CloseHandle可以关闭多种类型的对象,比如文件对象等,这里使用这个函数来关闭线程对象。调用时,hObject为待关闭的线程对象的句柄。

说使用这种方法可能会引发内存泄漏问题,其实不完全正确。那为什么会引起内存的泄漏呢?因为当线程的函数用到了C的标准库的时候,很容易导致冲突,所以在创建VC的工程时,系统提示是用单线程还是用多线程的库,因为在C的内部有很多的全局变量。例如,出错号、文件句柄等全局变量。

因为在C的库中有全局变量,这样用C的库时,如果程序中使用了标准的C程序库时,就很容易导致运行不正常,会引起很多的冲突。所以,微软和Borland都对C的库进行了一些改进。但是这个改进的一个条件就是,如果一个线程已经开始创建了,就应该创建一个结构来包含这些全局变量,接着把这些全局变量放入线程的上下文中和这个线程相关起来。这样,全局变量就会依赖于这个线程,不会引起冲突。

这样做就会有一个问题,什么时候这个线程开始创建呢?标准的Windows的API是不知道的,因为它是静态的库。这些库都是放在VC的LIB的目录内的,而线程函数是操作系统的函数。所以,VC和BC在创建线程时,都会用_beginThread来创建线程,再用_endThread来结束线程。这样,它们在创建线程的时候,就会知道什么时候创建了线程,并把全局变量放入某一结构中,让它和线程能关联起来。这样就不会发生冲突了。

很显然,要完成这个功能,首先需要分配结构表把全局变量包含起来。这个过程是在_beginThread时做的,而释放则是在_endTread内完成。

所以,当用_beginThread来创建,而用CloseHandle来关闭线程时,这时复制的全局结构就不会被释放了,这就有了内存的泄漏。这就是很多资料所说的内存泄漏问题的真正的原因。

其实,可以不用_beginThread和_endThread这一对函数。如果用CreateThread函数创建,用CloseHandle关闭,那么,与C有关的库就会用全局的,它们会引起冲突。所以,比较好的方法就是在线程内不用标准的C的库(可以使用Windows API的库函数)。这样就不会有什么问题,也就不会引起冲突。例如,字符串的操作函数、文件操作等。

当某个程序创建一个线程后,会产生一个线程的句柄,线程的句柄主要用来控制整个线程的运行,例如停止、挂起或设置线程的优先级等操作。


PeekNamedPipe 

预览一个管道中的数据,或取得与管道中的数据有关的信息

返回值折叠编辑本段

  Long,非零表示成功,零表示失败。会设置 GetLastError.

VB声明折叠编辑本段

  Declare Function PeekNamedPipe Lib "kernel32" Alias "PeekNamedPipe" (ByVal hNamedPipe As Long, lpBuffer As Any, ByVal nBufferSize As Long, lpBytesRead As Long, lpTotalBytesAvail As Long, lpBytesLeftThisMessage As Long) As Long

参数表折叠编辑本段

  
参数 类型及说明
hNamedPipe Long,指定一个管道的句柄。这并不一定是某个命名管道的句柄——匿名管道同样适用
lpBuffer Any,指定要装载数据的一个缓冲区的头一个字符。可以为零(使用ByVal 0&)
nBufferSize Long,lpBuffer缓冲区长度
lpBytesRead Long,保存装载到缓冲区的字符数量
lpTotalBytesAvail Long,保存管道中可用的字符数量
lpBytesLeftThisMessage Long,保存这次读操作后仍然保留在消息中的字符数。只能为那些基于消息的命名管道设置

注释折叠编辑本段

  由这个函数读入的数据实际并不能从管道中删除。如果要对一个管道进行轮询,了解是否有可能数据,那么使用这个函数特别理想.

VC++声明折叠编辑本段

   函数原型
BOOL WINAPI PeekNamedPipe(
__in HANDLE hNamedPipe, //管道句柄
__out_opt LPVOID lpBuffer, //读取输出缓冲区,可选
__in DWORD nBufferSize, //缓冲区大小
__out_opt LPDWORD lpBytesRead, //接收从管道中读取数据的变量的指针,可选
__out_opt LPDWORD lpTotalBytesAvail, //接收从管道读取的字节总数
__out_opt LPDWORD lpBytesLeftThisMessage
);

注释折叠

  参数
hNamedPipe [in] 
管道句柄。这个参数可以是一个命名管道实例句柄,返回,由CreateNamedPipe或CreateFile函数,或者它可以是一个匿名管道的读端句柄,返回由CREATEPIPE功能。句柄必须有GENERIC_READ权限的管道。
lpBuffer [out, optional] 
接收从管道读取数据的缓冲区的指针。如果没有数据要读取,此参数可以为NULL。
nBufferSize [in] 
lpBuffer参数以字节为单位,由指定的缓冲区大小。如果lpBuffer是NULL,则忽略此参数。
lpBytesRead [out, optional] 
接收从管道中读取的字节数的变量的指针。此参数可以为NULL,如果没有数据要读取。
lpTotalBytesAvail [out, optional] 
一个 指针变量,接收从管道读取的字节总数。此参数可以为NULL,如果没有数据要读取。
lpBytesLeftThisMessage [out, optional] 
指向剩余的字节数的变量的指针消息。此参数将是零字节类型的命名管道或匿名管道。此参数可以为NULL,如果没有数据要读取。

返回值折叠

  如果函数成功,返回值为非零。
如果函数失败,返回值是零。为了获得更多错误信息,调用GetLastError。

备注折叠

  PeekNamedPipe功能是类似ReadFile函数,有以下例外:
数据读取与CreateNamedPipe指定的模式。例如,与PIPE_TYPE_MESSAGE创建一个管道| PIPE_READMODE_MESSAGE。如果你改变模式与SetNamedPipeHandleState PIPE_READMODE_BYTE的,ReadFile函数将读取的字节模式,但PeekNamedPipe将继续在消息模式读取。
从管道读取数据不会被删除,从管道的缓冲区。
函数可以返回有关管内容的其他信息。
该函数总是返回立即在 单线程 应用程序,即使是在管道中没有数据。等待一个命名管道句柄(阻塞或非阻塞)模式,在功能上没有影响。
注意的PeekNamedPipe功能可以阻止线程执行任何I / O功能可以称为同步处理时,在一个多线程的应用程序相同的方式。为了避免这种情况,使用异步I / O创建一个管道句柄
如果指定的句柄是一个字节的只读模式命名管道句柄,函数读取所有可用的字节在nBufferSize指定的大小。为命名管道句柄消息只读模式,函数读取管道中的下一个消息。如果消息是较大比nBufferSize,该函数返回TRUE读取指定的字节数。在这种情况下,lpBytesLeftThisMessage将收到的消息中剩余的字节数。


ReadFile 

从文件指针指向的位置开始将数据读出到一个文件中, 且支持同步和异步操作,如果文件打开方式没有指明FILE_FLAG_OVERLAPPED的话,当程序调用成功时,它将实际读出文件的字节数保存到lpNumberOfBytesRead指明的地址空间中。FILE_FLAG_OVERLAPPED 允许对文件进行重叠操作如果文件要交互使用的话,当函数调用完毕时要记得调整文件指针。从文件中读出数据。与fread函数相比,这个函数要明显灵活的多。该函数能够操作通信设备、管道、套接字以及邮槽。

函数原型折叠编辑本段

BOOL ReadFile(

HANDLE hFile, //文件的句柄

LPVOID lpBuffer, //用于保存读入数据的一个缓冲区

DWORD nNumberOfBytesToRead, //要读入的字节数

LPDWORD lpNumberOfBytesRead, //指向实际读取字节数的指针

LPOVERLAPPED lpOverlapped //如文件打开时指定了FILE_FLAG_OVERLAPPED,那么必须,用这个参数引用一个特殊的结构。该结构定义了一次异步读取操作。否则,应将这个参数设为NULL  

FILE_FLAG_OVERLAPPED

文件或设备被打开或创建异步I / O。

当后续的I / O操作完成这个句柄,OVERLAPPED结构中指定的事件 将被设置为有信号状态。

如果这个标志被指定,该文件可用于同时读取和写入操作。

如果没有指定这个标志,然后被序列化I / O操作,即使调用读写函数指定一个OVERLAPPED结构。

功能说明折叠编辑本段

从文件指针指向的位置开始将数据读出到一个文件中, 且支持同步和异步操作,

如果文件打开方式没有指明FILE_FLAG_OVERLAPPED的话,当程序调用成功时,它将实际读出文件的字节数保存到lpNumberOfBytesRead指明的地址空间中。

FILE_FLAG_OVERLAPPED 允许对文件进行重叠操作

如果文件要交互使用的话,当函数调用完毕时要记得调整文件指针。

从文件中读出数据。与fread函数相比,这个函数要明显灵活的多。该函数能够操作通信设备、管道、套接字以及邮槽。

参数说明折叠编辑本段

HANDLE hFile, 需要读入数据的文件指针,这个指针指向的文件必须是GENERIC_READ 访问属性的文件。

LPVOID lpBuffer,接收数据的缓冲区。

DWORD nNumberOfBytesToRead,指定要读取的字节数。

LPDWORD lpNumberOfBytesRead,指向一个DWORD类型变量的指针,用来接收读取的字节数。如果下一个参数为NULL,那么一定要传入这个参数。

LPOVERLAPPED lpOverlapped OVERLAPPED结构体指针,如果文件是以FILE_FLAG_OVERLAPPED方式打开的话,那么这个指针就不能为NULL。

FILE_FLAG_OVERLAPPED 允许对文件进行重叠操作

返回值折叠编辑本段

调用成功,返回非0

调用不成功,返回为0

会设置GetLastError。如启动的是一次异步读操作,则函数会返回零值,并将ERROR_IO_PENDING设置成GetLastError的结果。如结果不是零值,但读入的字节数小于nNumberOfBytesToRead参数指定的值,表明早已抵达了文件的结尾。

应用实例折叠编辑本段

void ReadFile(char* str)

{

HANDLE pfile;

pfile = ::CreateFile(str,GENERIC_READ,0,NULL,OPEN_EXISTING,

FILE_ATTRIBUTE_NORMAL|FILE_FLAG_DELETE_ON_CLOSE,NULL); // 用这个函数比OpenFile好

if ( pfile == INVALID_HANDLE_VALUE)

{

MessageBox( NULL,"打开文件失败" ,"Error",MB_OK);

CloseHandle(pfile); // 一定注意在函数退出之前对句柄进行释放。

return;

}

DWORD filesize=GetFileSize(pfile,NULL);

char* buffer=new char[filesize+1]; // 最后一位为 '/0',C-Style 字符串的结束符。

DWORD readsize;

ReadFile(pfile,buffer,filesize,&readsize,NULL);

buffer[filesize]=0;

MessageBox(NULL,buffer,"Buffer Size",MB_OK);

// 善后工作

delete[] buffer; // 注意是delete[] 而不是 delete

CloseHandle(pfile); // 关闭句柄。

}

createprocess 编辑词条

WIN32API函数CreateProcess用来创建一个新的进程和它的主线程,这个新进程运行指定的可执行文件。

函数原型折叠编辑本段

BOOL CreateProcess

(    

LPCTSTRlpApplicationName,

LPTSTRlpCommandLine,

LPSECURITY_ATTRIBUTESlpProcessAttributes,

LPSECURITY_ATTRIBUTESlpThreadAttributes,

BOOLbInheritHandles,

DWORDdwCreationFlags,

LPVOIDlpEnvironment,

LPCTSTRlpCurrentDirectory,

LPSTARTUPINFOlpStartupInfo,

LPPROCESS_INFORMATIONlpProcessInformation

);

参数折叠编辑本段

1.lpApplicationName:

指向一个NULL结尾的、用来指定可执行模块的字符串。

这个字符串可以是可执行模块的绝对路径,也可以是相对路径,在后一种情况下,函数使用当前驱动器和目录建立可执行模块的路径。

这个参数可以被设为NULL,在这种情况下,可执行模块的名字必须处于 lpCommandLine 参数的最前面并由空格符与后面的字符分开。

这个被指定的模块可以是一个Win32应用程序。如果适当的子系统在当前计算机上可用的话,它也可以是其他类型的模块(如MS-DOS 或 OS/2)。

在Windows NT中,如果可执行模块是一个16位的应用程序,那么这个参数应该被设置为NULL并且应该在lpCommandLine参数中指定可执行模块的名称。16位的应用程序是以DOS虚拟机或Win32上的Windows(WOW) 为进程的方式运行。

2.lpCommandLine:

指向一个以NULL结尾的字符串,该字符串指定要执行的命令行。

这个参数可以为空,那么函数将使用lpApplicationName参数指定的字符串当做要运行的程序的命令行。

如果lpApplicationName和lpCommandLine参数都不为空,那么lpApplicationName参数指定将要被运行的模块,lpCommandLine参数指定将被运行的模块的命令行。新运行的进程可以使用GetCommandLine函数获得整个命令行。C语言程序可以使用argc和argv参数。

如果lpApplicationName参数为空,那么这个字符串中的第一个被空格分隔的要素指定可执行模块名。如果文件名不包含扩展名,那么.exe将被假定为默认的扩展名。如果文件名以一个点(.)结尾且没有扩展名,或文件名中包含路径,.exe将不会被加到后面。如果文件名中不包含路径,Windows将按照如下顺序寻找这个可执行文件:

1).当前应用程序的目录。

2).父进程的目录。

3).Windows 95:Windows系统目录,可以使用GetSystemDirectory函数获得。

Windows NT:32位Windows系统目录。可以使用GetSystemDirectory函数获得,目录名是SYSTEM32。

4).在Windows NT中:16位Windows系统目录。不可以使用Win32函数获得这个目录,但是它会被搜索,目录名是SYSTEM。

5).Windows目录。可以使用GetWindowsDirectory函数获得这个目录。

6).列在PATH环境变量中的目录。

如果被创建的进程是一个以MS-DOS或16位Windows为基础的应用程序,lpCommandLine参数应该是一个以可执行文件的文件名作为第一个要素的绝对路径,因为这样做可以使32位Windows程序工作的很好,这样设置lpCommandLine参数是最强壮的。

注意:Visual C 2005以后的版本中,如果向CreateProcess函数传递一个常量指针作为命令行参数的话,将会发生访问违规错误。原因是系统在执行该函数时会修改lpCommandLine所指向的字符串(比如解释转义字符等)。因此,在调用此函数前,应该定义一个临时字符数组变量来保存命令行参数,并将这个临时变量作为lpCommandLine参数传递.

传递参数例子:

LPTSTR szCmdline = _tcsdup(TEXT(c:\\test.bat));//用szCmdline做CreateProcess第2参数,VS2008测试通过.

wchar_t* szCmdline = wcsdup(TEXT(notepad));//对于Unicode版本使用此版本头文件(#includeCstring)。vs2010测试通过。

3.lpProcessAttributes:

指向一个SECURITY_ATTRIBUTES结构体,这个结构体决定是否返回的句柄可以被子进程继承。如果lpProcessAttributes参数为空(NULL),那么句柄不能被继承。

在Windows NT中:SECURITY_ATTRIBUTES结构的lpSecurityDescriptor成员指定了新进程的安全描述符,如果参数为空,新进程使用默认的安全描述符。

在Windows95中:SECURITY_ATTRIBUTES结构的lpSecurityDescriptor成员被忽略。

4.lpThreadAttributes:

指向一个SECURITY_ATTRIBUTES结构体,这个结构体决定是否返回的指向线程的句柄可以被子进程继承。如果lpThreadAttributes参数为空(NULL),那么句柄不能被继承。

在Windows NT中,SECURITY_ATTRIBUTES结构的lpSecurityDescriptor成员指定了主线程的安全描述符,如果参数为空,主线程使用默认的安全描述符。

在Windows95中:SECURITY_ATTRIBUTES结构的lpSecurityDescriptor成员被忽略。

5.bInheritHandles:

指示新进程是否从调用进程处继承了句柄。

如果参数的值为真,调用进程中的每一个可继承的打开句柄都将被子进程继承。被继承的句柄与原进程拥有完全相同的值和访问权限。

6.dwCreationFlags:

指定附加的、用来控制优先类和进程的创建的标志。以下的创建标志可以以除下面列出的方式外的任何方式组合后指定。

⑴值:CREATE_DEFAULT_ERROR_MODE

含义:新的进程不继承调用进程的错误模式。CreateProcess函数赋予新进程当前的默认错误模式作为替代。应用程序可以调用SetErrorMode函数设置当前的默认错误模式。

这个标志对于那些运行在没有硬件错误环境下的多线程外壳程序是十分有用的。

对于CreateProcess函数,默认的行为是为新进程继承调用者的错误模式。设置这个标志以改变默认的处理方式。

⑵值:CREATE_NEW_CONSOLE

含义:新的进程将使用一个新的控制台,而不是继承父进程的控制台。这个标志不能与DETACHED_PROCESS标志一起使用。

⑶值:CREATE_NEW_PROCESS_GROUP

含义:新进程将使一个进程树的根进程。进程树中的全部进程都是根进程的子进程。新进程树的用户标识符与这个进程的标识符是相同的,由lpProcessInformation参数返回。进程树经常使用GenerateConsoleCtrlEvent函数允许发送CTRL C或CTRL BREAK信号到一组控制台进程。

⑷值:CREATE_SEPARATE_WOW_VDM

含义:(只适用于Windows NT)这个标志只有当运行一个16位的Windows应用程序时才是有效的。如果被设置,新进程将会在一个私有的虚拟DOS机(VDM)中运行。另外,默认情况下所有的16位Windows应用程序都会在同一个共享的VDM中以线程的方式运行。单独运行一个16位程序的优点是一个应用程序的崩溃只会结束这一个VDM的运行;其他那些在不同VDM中运行的程序会继续正常的运行。同样的,在不同VDM中运行的16位Windows应用程序拥有不同的输入队列,这意味着如果一个程序暂时失去响应,在独立的VDM中的应用程序能够继续获得输入。

⑸值:CREATE_SHARED_WOW_VDM

含义:(只适用于Windows NT)这个标志只有当运行一个16位的Windows应用程序时才是有效的。如果WIN.INI中的Windows段的DefaultSeparateVDM选项被设置为真,这个标识使得CreateProcess函数越过这个选项并在共享的虚拟DOS机中运行新进程。

⑹值:CREATE_SUSPENDED

含义:新进程的主线程会以暂停的状态被创建,直到调用ResumeThread函数被调用时才运行。

⑺值:CREATE_UNICODE_ENVIRONMENT

含义:如果被设置,由lpEnvironment参数指定的环境块使用Unicode字符,如果为空,环境块使用ANSI字符。

⑻值:DEBUG_PROCESS

含义:如果这个标志被设置,调用进程将被当做一个调试程序,并且新进程会被当做被调试的进程。系统把被调试程序发生的所有调试事件通知给调试器。

如果你使用这个标志创建进程,只有调用进程(调用CreateProcess函数的进程)可以调用WaitForDebugEvent函数。

⑼值:DEBUG_ONLY_THIS_PROCESS

含义:如果此标志没有被设置且调用进程正在被调试,新进程将成为调试调用进程的调试器的另一个调试对象。如果调用进程没有被调试,有关调试的行为就不会产生。

⑽值:DETACHED_PROCESS

含义:对于控制台进程,新进程没有访问父进程控制台的权限。新进程可以通过AllocConsole函数自己创建一个新的控制台。这个标志不可以与CREATE_NEW_CONSOLE标志一起使用。

dwCreationFlags参数

还用来控制新进程的优先类,优先类用来决定此进程的线程调度的优先级。如果下面的优先级类标志都没有被指定,那么默认的优先类是NORMAL_PRIORITY_CLASS,除非被创建的进程是IDLE_PRIORITY_CLASS。在这种情况下子进程的默认优先类是IDLE_PRIORITY_CLASS。

可以选择下面的标志中的一个:

优先级:HIGH_PRIORITY_CLASS

含义:指示这个进程将执行时间临界的任务,所以它必须被立即运行以保证正确。这个优先级的程序优先于正常优先级或空闲优先级的程序。一个例子是Windows任务列表,为了保证当用户调用时可以立刻响应,放弃了对系统负荷的考虑。确保在使用高优先级时应该足够谨慎,因为一个高优先级的CPU关联应用程序可以占用几乎全部的CPU可用时间。

优先级:IDLE_PRIORITY_CLASS

含义:指示这个进程的线程只有在系统空闲时才会运行并且可以被任何高优先级的任务打断。例如屏幕保护程序。空闲优先级会被子进程继承。

优先级:NORMAL_PRIORITY_CLASS

含义:指示这个进程没有特殊的任务调度要求。

优先级:REALTIME_PRIORITY_CLASS

含义:指示这个进程拥有可用的最高优先级。一个拥有实时优先级的进程的线程可以打断所有其他进程线程的执行,包括正在执行重要任务的系统进程。例如,一个执行时间稍长一点的实时进程可能导致磁盘缓存不足或鼠标反映迟钝。

7.lpEnvironment:

指向一个新进程的环境块。如果此参数为空,新进程使用调用进程的环境。

一个环境块存在于一个由以NULL结尾的字符串组成的块中,这个块也是以NULL结尾的。每个字符串都是name=value的形式。

因为相等标志被当做分隔符,所以它不能被环境变量当做变量名。

与其使用应用程序提供的环境块,不如直接把这个参数设为空,系统驱动器上的当前目录信息不会被自动传递给新创建的进程。对于这个情况的探讨和如何处理,请参见注释一节。

环境块可以包含Unicode或ANSI字符。如果lpEnvironment指向的环境块包含Unicode字符,那么dwCreationFlags字段的CREATE_UNICODE_ENⅥRONMENT标志将被设置。如果块包含ANSI字符,该标志将被清空。

请注意一个ANSI环境块是由两个零字节结束的:一个是字符串的结尾,另一个用来结束这个快。一个Unicode环境块是由四个零字节结束的:两个代表字符串结束,另两个用来结束块。

8.lpCurrentDirectory:

指向一个以NULL结尾的字符串,这个字符串用来指定子进程的工作路径。这个字符串必须是一个包含驱动器名的绝对路径。如果这个参数为空,新进程将使用与调用进程相同的驱动器和目录。这个选项是一个需要启动应用程序并指定它们的驱动器和工作目录的外壳程序的主要条件。

9.lpStartupInfo:

指向一个用于决定新进程的主窗体如何显示的STARTUPINFO结构体。

   GetStartupInfo
The GetStartupInfo function retrieves the contents of the STARTUPINFO structure that was specified when the calling process was created. 
VOID GetStartupInfo(
LPSTARTUPINFO lpStartupInfo // address of STARTUPINFO structure
);
Parameters
lpStartupInfo 
Pointer to a STARTUPINFO structure that is filled in by the function. 
Return Values
This function does not return a value. 
Remarks
The STARTUPINFO structure was specified by the process that created the calling process. It can be used to specify properties associated with the main window of the calling process. 
QuickInfo
Windows NT: Requires version 3.1 or later.
Windows: Requires Windows 95 or later.
Windows CE: Unsupported.
Header: Declared in winbase.h.
Import Library: Use kernel32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT.
中文翻译:
GetStartupInfo
函数功能描述:该函数返回进程在启动时被指定的 STARTUPINFO 结构
VOID GetStartupInfo(
LPSTARTUPINFO lpStartupInfo 
);
参数
lpStartupInfo 
用来存放要获取的 STARTUPINFO 结构
返回值
该函数没有返回值
STARTUPINFO 结构由当前进程的父进程指定,它能够用于指定当前进程主窗口的属性。
Windows NT: 要求3.1或更高版本
Windows: 要求windows 95或更高版本
Windows CE: 不支持。
头文件 winbase.h.
库文件 kernel32.lib
Unicode 在Windows NT上有Unicode 和 ANSI 两个版本

GetStartupInfoA折叠编辑本段

  VB声明 
Declare Sub GetStartupInfo Lib "kernel32" Alias "GetStartupInfoA" (lpStartupInfo As STARTUPINFO) 
说明 获取一个进程的启动信息 
参数表 参数 类型及说明 lpStartupInfo STARTUPINFO,指定一个STARTUPINFO结构,用于最终载入进程的启动信息 
易语言声明
.版本 2
.DLL命令 GetStartupInfoA, 整数型, "kernel32", "GetStartupInfoA", , 获取启动信息
.参数 lpStartupInfo, STARTUPINFO, 传址, 启动信息

10.lpProcessInformation:

指向一个用来接收新进程的识别信息的PROCESS_INFORMATION结构体。

返回值折叠编辑本段

如果函数执行成功,返回非零值。

如果函数执行失败,返回零,可以使用GetLastError函数获得错误的附加信息。

注释:

CreateProcess函数用来运行一个新程序。WinExec和LoadModule函数依旧可用,但是它们同样通过调用CreateProcess函数实现。

另外CreateProcess函数除了创建一个进程,还创建一个线程对象。这个线程将连同一个已初始化了的堆栈一起被创建,堆栈的大小由可执行文件的文件头中的描述决定。线程由文件头处开始执行。

新进程和新线程的句柄被以全局访问权限创建。对于这两个句柄中的任一个,如果没有安全描述符,那么这个句柄就可以在任何需要句柄类型作为参数的函数中被使用。当提供安全描述符时,在接下来的时候当句柄被使用时,总是会先进行访问权限的检查,如果访问权限检查拒绝访问,请求的进程将不能使用这个句柄访问这个进程。

这个进程会被分配给一个32位的进程标识符。直到进程中止这个标识符都是有效的。它可以被用来标识这个进程,或在OpenProcess函数中被指定以打开这个进程的句柄。进程中被初始化了的线程一样会被分配一个32位的线程标识符。这个标识符直到线程中止都是有效的且可以用来在系统中唯一标识这个线程。这些标识符在PROCESS_INFORMATION结构体中返回。

当在lpApplicationName或lpCommandLine参数中指定应用程序名时,应用程序名中是否包含扩展名都不会影响运行,只有一种情况例外:一个以.com为扩展名的MS-DOS程序或Windows程序必须包含.com扩展名。

调用进程可以通过WaitForInputIdle函数来等待新进程完成它的初始化并等待用户输入。这对于父进程和子进程之间的同步是极其有用的,因为CreateProcess函数不会等待新进程完成它的初始化工作。举例来说,在试图与新进程关联的窗口之前,进程应该先调用WaitForInputIdle。

首选的结束一个进程的方式是调用ExitProcess函数,因为这个函数通知这个进程的所有动态链接库(DLLs)程序已进入结束状态。其他的结束进程的方法不会通知关联的动态链接库。注意当一个进程调用ExitProcess时,这个进程的其他线程没有机会运行其他任何代码(包括关联动态链接库的终止代码)。

ExitProcess,ExitThread,CreateThread,CreateRemoteThread,当一个进程启动时(调用了CreateProcess的结果)是在进程中序列化进行的。在一段地址空间中,同一时间内这些事件中只有一个可以发生。这意味着下面的限制将保留:

*在进程启动和DLL初始化阶段,新的线程可以被创建,但是直到进程的DLL初始化完成前它们都不能开始运行。

*在DLL初始化或卸下例程中进程中只能有一个线程。

*直到所有的线程都完成DLL初始化或卸下后,ExitProcess函数才返回。

在进程中的所有线程都终止且进程所有的句柄和它们的线程被通过调用CloseHandle函数终止前,进程会留在系统中。进程和主线程的句柄都必须通过调用CloseHandle函数关闭。如果不再需要这些句柄,最好在创建进程后立刻关闭它们。

当进程中最后一个线程终止时,下列的事件发生:

*所有由进程打开的对象都会关闭。

*进程的终止状态(由GetExitCodeProcess函数返回)从它的初始值STILL_ACTⅣE变为最后一个结束的线程的结束状态。

*主线程的线程对象被设置为标志状态,供其他等待这个对象的线程使用。

*进程对象被设置为标志状态,供其他等待这个对象的线程使用。

假设当前在C盘上的目录是\MSVC\MFC且有一个环境变量叫做C:,它的值是C:\MSVC\MFC,就像前面lpEnvironment中提到过的那样,这样的系统驱动器上的目录信息在CreateProcess函数的lpEnvironment参数不为空时不会被自动传递到新进程里。一个应用程序必须手动地把当前目录信息传递到新的进程中。为了这样做,应用程序必须直接创建环境字符串,并把它们按字母顺序排列(因为Windows NT和Windows 95使用一种简略的环境变量),并把它们放进lpEnvironment中指定的环境块中。类似的,他们要找到环境块的开头,又要重复一次前面提到的环境块的排序。

一种获得驱动器X的当前目录变量的方法是调用GetFullPathName(x:,..)。这避免了一个应用程序必须去扫描环境块。如果返回的绝对路径是X:\,就不需要把这个值当作一个环境数据去传递了,因为根目录是驱动器X上的新进程的默认当前目录。

由CreateProcess函数返回的句柄对于进程对象具有PROCESS_ALL_ACCESS的访问权限。

由lpcurrentDirectory参数指定的当前目录室子进程对象的当前目录。lpCommandLine参数指定的第二个项目是父进程的当前目录。

对于Windows NT,当一个进程在指定了CREATE_NEW_PROCESS_GROUP的情况下被创建时,一个对于SetConsoleCtrlHandler(NULL,True)的调用被用在新的进程上,这意味着对新进程来说CTRL C是无效的。这使得上层的外科程序可以自己处理CTRL C信息并有选择的把这些信号传递给子进程。CTRL BREAK依旧有效,并可被用来中断进程/进程树的执行。

安全注释:

第一个参数lpApplicationName可能是空,这种情况下,可执行文件的名字必须在lpCommandLine中,lpCommandLine参数中可以包含空格。如果可执行文件或路径中包含空格,那么就会有执行不正确文件的风险,这是由于这个函数解析空格的方法引起的。例如:下边这个例子就很危险,因为它试图运行Program.exe文件,如果这个文件存在,它就会代替MyApp.exe文件的运行。

CreateProcess(NULL,”C:\\Program Files\\MyApp.exe”,…….)

如果有恶意的用户在系统编写了一个名为Program.exe的文件,那么任何调用CreateProcess函数,且在文件路径中使用Program Files文件夹的参数,都有可能会运行Program.exe文件,而不是运行本来打算运行的文件。

要避免这个问题,可以不要将NULL值传递给lpApplicationName参数,或者在lpCommandLine中使用双引号(转义符)括起可执行文件的全路径名,如下所示:

CreateProcess(NULL,”\”C:\\Program Files\\MyApp.exe\” -L -S”,…….)

-L和-S是MyApp.exe可执行文件的参数。

最后要说明的一点是:在lpApplicationName中的参数和lpCommandLine中的第一个参数是一样的,有人说显得有些重复,其实这样做纯粹是一种被公认化了习惯!

参见

AllocConsole,CloseHandle,CreateRemoteThread,CreateThread,ExitProcess,ExitThread,GenerateConsoleCtrlEvent,GetCommandLine,GetEnvironmentStrings,GetExitCodeProcess,GetFullPathName,GetStartupInfo,GetSystemDirectory,GetWindowsDirectory,LoadModule,OpenProcess,PROCESS_INFORMATION,ResumeThread,SECURITY_ATTRIBUTES,SetConsoleCtrlHandler,SetErrorMode,STARTUPINFO,TerminateProcess,WaitForInputIdle,WaitForDebugEvent,WinExec

快捷信息:

导入库:kernel32.lib

头文件:Winbase.h

MFC代码折叠编辑本段

//因为win7开始后更多的使用管理员权限,所以CreateProcessWithLogonW更多的被使用。同样的功能的还有CreateProcessAsUser和CreateProcessWithTokenW。

//头文件添加略去了(include Windows.h),配合管道读取回传值

//参考了MSDN相关条目,自行修改和DEBUG可用

BOOL CreateMyProcess(CString strCommand,DWORD dwReturn,CString strLog,CString strPwd)

{

HANDLE hToken;

dwReturn = -1;

strLog = _T();

//尝试登陆管理员账户

if(!LogonUserW_TAdministrator),NULL,strPwd,

LOGON32_LOGON_INTERACTIVE,LOGON32_PROVIDER_DEFAULT,hToken)) {

int iError = GetLastError();

strLog.Format(_T(Error On LogonUserW(),error code is %d.),iError);

return FALSE;

}

BOOL blResult = FALSE;

SECURITY_ATTRIBUTES sa;

HANDLE hRead,hWrite;

sa.nLength = sizeof(SECURITY_ATTRIBUTES);

sa.lpSecurityDescriptor = NULL;

sa.bInheritHandle = TRUE;

//创建管道

if (!CreatePipe(hRead,hWrite,sa,0))

{

strLog = _T(Error On CreatePipe());

return FALSE;

}

STARTUPINFO si = { sizeof(si) }; // 将cb成员初始化为sizeof(si),其他成员初始化为0

::GetStartupInfo(si);

si.hStdError = hWrite;

si.hStdOutput = hWrite;

si.wShowWindow = SW_HIDE;

si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;

PROCESS_INFORMATION pi;

CString strInfo = _T();

ZeroMemory(pi,sizeof(pi));

//管理员方式启动进程

if (!CreateProcessWithLogonW(_T(Administrator), NULL,strPwd,

LOGON_WITH_PROFILE, NULL, strCommand.GetBuffer(),

CREATE_UNICODE_ENVIRONMENT, NULL, NULL, si, pi))

{

int iError = GetLastError();

strLog.Format(_T(Error On CreateProcessWithLogonW(),error code is %d.),iError);

CloseHandle(hWrite);

CloseHandle(hRead);

return FALSE;

}

CloseHandle(hWrite);

char buffer


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值