DLL中的函数返回值可以是cstring mid函数吗

C#调C++的dll的函数
C#调C++的dll的函数
[摘要:C++ struct HHFC_SET { char* UID; }; extern "C" __declspec(dllexport) int PReadUID(HHFC_SET* mystruct, char* lpKeyNo, LPTSTR lpKeyNo2 ) { //int a=5; CString ds="sea中国"; //wchar_t a[] = L"sea"; //lpKeyNo = (LPTSTR)(LPCTSTR)a; //l]
C++struct HHFC_SET{&char* &UID;&&int & &&&&};extern "C" __declspec(dllexport) int &PReadUID(HHFC_SET* mystruct, char* lpKeyNo, LPTSTR lpKeyNo2 ){&& & & //int a=5;&& & & CString ds="sea中国";
& //wchar_t a[] = L"sea";&
& //lpKeyNo = (LPTSTR)(LPCTSTR)a;
&//lpKeyNo = L'中国a';
&strcpy(lpKeyNo,"中国aabbbcccc");
&wcscpy(lpKeyNo2,L"中国aabbbcccc");
&//lpKeyNo[0] = L'a';
&//lpKeyNo[1] = L'b';
&//lpKeyNo[2] = L'c';
&//lpKeyNo[3] = L'';
&//::MessageBox(NULL, lpKeyNo, L"info", MB_OK);
// &mystruct-&UID=ds.GetBuffer(ds.GetLength()+1);
&mystruct-&UID="seaaa中国";
&&return 5;}C#using Susing System.Runtime.InteropSusing System.Tnamespace PInvoke{&& &/// &summary&&& &/// Ivoke 的摘要说明。&& &/// &/summary&&& &///&&& &public class Ivoke&& &{&& & & &[DllImport("standerMFC.dll", EntryPoint = "PReadUID", CharSet = CharSet.Ansi)]&& & & &//nPort:1代表COM1,返回-1代表已经打开COM PORT失败,0代表COM已经打开,返回其它值表示打开对应的COM&& & & &public static extern int PReadUID(ref HHFC_SET stru,&&& & & & & &[MarshalAs(UnmanagedType.LPStr)] StringBuilder sb,&& & & & & &[MarshalAs(UnmanagedType.LPWStr)] StringBuilder sb2);&& &}&& &[StructLayout(LayoutKind.Sequential)]&& &public struct HHFC_SET&& &{&& & & &[MarshalAs(UnmanagedType.LPStr)]&& & & &public String U&& & & &[MarshalAs(UnmanagedType.I4)]&& & & &&& &}}namespace PInvoke{ /// &summary& /// Class1 的摘要说明。 /// &/summary& class Class1 {
/// &summary&
/// 应用程序的主入口点。
/// &/summary&
[STAThread]
static void Main(string[] args)
// TODO: 在此处添加代码以启动应用程序
HHFC_SET stru=new HHFC_SET ();
stru.Uid="";
& & & &Console.WriteLine(stru.Uid);&& & & & & &StringBuilder sb = new StringBuilder(80);&& & & & & &StringBuilder sb2 = new StringBuilder(80);&& & & & & &int a = Ivoke.PReadUID(ref stru, sb, sb2);&& & & & & &//Ivoke.GetUsbkeyNo();
Console.WriteLine(stru.Uid);
Console.Read();
} }}注意:char* &用&UnmanagedType.LPStrwchar_t* 用&UnmanagedType.LPWStrC#中调用非托管的DLL及参数传递本篇文章来源于:开发学院
& 原文链接:/111.php微软的.NET框架的优点之一是它提供了独立于语言的开发平台。你可以在VB、C++、C#等语言中编写一些类,而在其它语言中使用(源于.NET中使用了CLS),你甚至可以从另一种语言编写的类中继承。但是你要是想调用以前的非托管DLL,微软的.NET框架的优点之一是它提供了独立于语言的开发平台。你可以在VB、C++、C#等语言中编写一些类,而在其它语言中使用(源于.NET中使用了CLS),你甚至可以从另一种语言编写的类中继承。但是你要是想调用以前的非托管DLL,那又会怎么样呢?你必须以某种方式将.NET对象转换为结构体、char *、函数指针等类型。这也就是说,你的参数必须被marshal(注:不知道中文名称该叫什么,英文中指的是为了某个目的而组织人或事物,参见这里,此处指的是为了调用非托管函数而进行的参数转换)。&& &C#中使用DLL函数之前,你必须使用DllImport声明要调用的函数:public class Win32 {&&[DllImport("User32.Dll")]&&public static extern void SetWindowText(int h, String s);&&// 函数原型为:BOOL SetWindowText(HWND hWnd, LPCTSTR lpString);} & &DllImport告诉编译器被调函数的入口在哪里,并且将该入口绑定到类中你声明的函数。你可以给这个类起任意的名字,我给它命名为Win32。你甚至可以将类放到命名空间中,具体参见图一。要编译Win32API.cs,输入:csc /t:library /out:Win32API.dll Win32API.cs & &这样你就拥有了Win32API.dll,并且你可以在任意的C#项目中使用它:using Win32API;int hwnd = // get it...String s = "I'm so cute."Win32.SetWindowText(hwnd, s); & &编译器知道去user32.dll中查找函数SetWindowText,并且在调用前自动将String转换为LPTSTR (TCHAR*)。很惊奇是吧!那么.NET是如何做到的呢?每种C#类型有一个默认的marshal类型,String对应LPTSTR。但你若是试着调用GetWindowText会怎么样呢(此处字符串作为out参数,而不是in参数)?它无法正常调用,是因为String是无法修改的,你必须使用StringBuilder:using System.T // for StringBuilderpublic class Win32 {&&[DllImport("user32.dll")]&&public static extern int GetWindowText(int hwnd,&& &StringBuilder buf, int nMaxCount);&&// 函数原型:int GetWindowText(HWND hWnd, LPTSTR lpString, int nMaxCount);} & &StringBuilder默认的marshal类型是LPTSTR,此时GetWindowText可以修改你的字符串:int hwnd = // get it...StringBuilder cb = new StringBuilder(256);Win32.GetWindowText(hwnd, sb, sb.Capacity); & &如果默认的类型转换无法满足你的要求,比如调用函数GetClassName,它总是将参数转换为类型LPSTR (char *),即便在定义Unicode的情况下使用,CLR仍然会将你传递的参数转换为TCHAR类型。不过不用着急,你可以使用MarshalAs覆盖掉默认的类型:[DllImport("user32.dll")]public static extern int GetClassName(int hwnd,&&[MarshalAs(UnmanagedType.LPStr)] StringBuilder buf,&&int nMaxCount);&&// 函数原型:int GetClassNameA(HWND hWnd, LPTSTR lpClassName, int nMaxCount); & &这样当你调用GetClassName时,.NET将字符串作为ANSI字符传递,而不是宽字符。&& &结构体和回调函数类型的参数又是如何传递的呢?.NET有一种方法可以处理它们。举个简单的例子,GetWindowRect,这个函数获取窗口的屏幕坐标,C++中我们这么处理:// in C/C++RECTHWND hwnd = FindWindow("foo",NULL);::GetWindowRect(hwnd, &rc); & 你可以使用C#结构体,只需使用另外一种C#属性StructLayout:[StructLayout(LayoutKind.Sequential)]public struct RECT {&&&&&&&&} & &一旦你定义了上面的结构体,你可以使用下面的函数声明形式 :[DllImport("user32.dll")]public static extern int&&&GetWindowRect(int hwnd, ref RECT rc);&&// 函数原型:BOOL GetWindowRect(HWND hWnd, LPRECT lpRect);&& &使用ref标识很重要,以至于CLR(通用语言运行时)将RECT变量作为引用传递到函数中,而不是无意义的栈拷贝。定义了GetWindowRect之后,你就可以采用下面的方式调用:RECT rc = new RECT();int hwnd = // get it ...Win32.GetWindowRect(hwnd, ref rc); & &注意你同样需要像声明中的那样使用ref关键字。C#结构体默认的marshal类型是LPStruct,因此没有必要使用MarshalAs。但如果你使用了类RECT而不是结构体RECT,那么你必须使用如下的声明形式:// if RECT is a class, not struct[DllImport("user32.dll")]public static extern int&&&GetWindowRect(int hwnd,&&& &[MarshalAs(UnmanagedType.LPStruct)] RECT rc); & &C#和C++一样,一件事情有很多中实现方式。System.Drawing中已经有Rectangle结构体,用来处理矩形,那有为什么要“重新发明轮子”呢?[DllImport("user32.dll")]public static extern int GetWindowRect(int hwnd, ref Rectangle rc); & &最后,又是怎样从C#中传递回调函数到非托管代码中的呢?你所要做的就是委托(delegate)。delegate bool EnumWindowsCB(int hwnd, int lparam); & &一旦你声明了你的回调函数,那么你需要调用的函数声明为:[DllImport("user32")]public static extern int&&&EnumWindows(EnumWindowsCB cb, int lparam);&&// 函数原型:BOOL EnumWindows(WNDENUMPROC lpEnumFunc, LPARAM lParam);&& &由于上面的委托仅仅是声明了委托类型,你需要在你的类中提供实际的回调函数代码。// in your classpublic static bool MyEWP(int hwnd, int lparam) {&&// do something&&} & &然后传递给相应的委托变量:EnumWindowsCB cb = new EnumWindowsCB(MyEWP);Win32.EnumWindows(cb, 0); & &你可能注意到参数lparam。在C语言中,如果你传递参数LPARAM给EnumWindows,Windows将它作为参数调用你的回调函数。通常lparam是包含了你要做的事情的上下文结构体或类指针,记住,在.NET中没有指针的概念!那该怎么做呢?上面的例子中,你可以申明lparam为IntPtr类型,并且使用GCHandle来封装它:// lparam is IntPtr nowdelegate bool EnumWindowsCB(int hwnd, & & IntPtr lparam);// wrap object in GCHandleMyClass obj = new MyClass();GCHandle gch = GCHandle.Alloc(obj);EnumWindowsCB cb = new EnumWindowsCB(MyEWP);&& Win32.EnumWindows(cb, (IntPtr)gch);&& gch.Free(); & &不要忘了使用完之后手动释放它!有时,你需要按照以前那种方式在C#中释放内存。可以使用GCHandle.Target的方式在你的回调函数中使用“指针”。public static bool MyEWP(int hwnd, IntPtr param) {&&GCHandle gch = (GCHandle)&&MyClass c = (MyClass)gch.T&&// ... use it&&} & & &图2是将EnumWindows封装到数组中的类。你只需要按如下的方式使用即可,而不要纠结于委托和回调中。WindowArray wins = new WindowArray();foreach (int hwnd in wins) {&// do something} & &关于委托代码和非委托代码之间交互的更多内容,你可以参考.NET文档中的“平台调用教程”。&C#调用dll时的类型转换总结
作为输入参数转为,通过Encoding类对这个string[]进行编码后得到的一个char[]
作为输出参数转为,通过Encoding类对这个byte[]进行解码,得到字符串
中的声明:
中的调用:
或(更常用一些)
: 声音类型其中的声音类型为枚举类型中的某一值。 : 用户需要自己定义一个枚举类型:
           
中导入该函数:
中调用该函数:
: 使用结构指针作为参数的函数:
中该结构体的定义:
           
: 用户自定义相应的结构体:
           
中导入该函数:
  中调用该函数:
初始化赋值
对于字符串的处理分为以下几种情况: 字符串常量指针的处理(),也适应于字符串常量的处理,中的类型是不可变的类型。 字符串缓冲区的处理(),即对于变长字符串的处理,中可用作缓冲区 :
: 函数声明:
    函数调用:
备注: 中的是为了说明自动地调用该函数相关的版本或者版本
变长字符串处理: : 函数声明:
          函数调用:
具有内嵌字符数组的结构: :
                                   
                 
具有回调的函数
       窗口实例的句柄   回调函数          用于回调函数的值
回调函数的声明:
  桌面名称      用户定义的值
: 将回调函数的声明转化为委托:
      该函数在中的声明: [DllImport("user32.dll", CharSet = CharSet.Auto)]static extern
bool EnumDesktops( &IntPtr windowStation, &EnumDesktopProc callback, &int lParam); 该表对中调用函数,以及编写的时参数及返回值的转换做了一个小的总结,如果想进一步了解这方面内容的话,可以参照中“互操作封送处理”一节。
感谢关注 Ithao123C/c++频道,是专门为互联网人打造的学习交流平台,全面满足互联网人工作与学习需求,更多互联网资讯尽在 IThao123!
Laravel是一套简洁、优雅的PHP Web开发框架(PHP Web Framework)。它可以让你从面条一样杂乱的代码中解脱出来;它可以帮你构建一个完美的网络APP,而且每行代码都可以简洁、富于表达力。
Hadoop是一个由Apache基金会所开发的分布式系统基础架构。
用户可以在不了解分布式底层细节的情况下,开发分布式程序。充分利用集群的威力进行高速运算和存储。
Hadoop实现了一个分布式文件系统(Hadoop Distributed File System),简称HDFS。HDFS有高容错性的特点,并且设计用来部署在低廉的(low-cost)硬件上;而且它提供高吞吐量(high throughput)来访问应用程序的数据,适合那些有着超大数据集(large data set)的应用程序。HDFS放宽了(relax)POSIX的要求,可以以流的形式访问(streaming access)文件系统中的数据。
Hadoop的框架最核心的设计就是:HDFS和MapReduce。HDFS为海量的数据提供了存储,则MapReduce为海量的数据提供了计算。
产品设计是互联网产品经理的核心能力,一个好的产品经理一定在产品设计方面有扎实的功底,本专题将从互联网产品设计的几个方面谈谈产品设计
随着国内互联网的发展,产品经理岗位需求大幅增加,在国内,从事产品工作的大部分岗位为产品经理,其实现实中,很多从事产品工作的岗位是不能称为产品经理,主要原因是对产品经理的职责不明确,那产品经理的职责有哪些,本专题将详细介绍产品经理的主要职责
IThao123周刊C总结_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
||文档简介
中级工程师|
总评分4.5|
浏览量3697
&&面​试​宝​典
阅读已结束,如果下载本文需要使用1下载券
想免费下载本文?
下载文档到电脑,查找使用更方便
还剩27页未读,继续阅读
你可能喜欢CreateProcess_百度百科
CreateProcess
WIN32API函数CreateProcess用来创建一个新的进程和它的,这个新进程运行指定的。
CreateProcess函数原型
BOOL CreateProcess
LPCTSTR lpApplicationName,
LPTSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCTSTR lpCurrentDirectory,
LPSTARTUPINFO lpStartupInfo,
lpProcessInformation
CreateProcess参数
lpApplicationName
指向一个NULL结尾的、用来指定可执行模块的字符串。
这个字符串可以是可执行模块的,也可以是,在后一种情况下,函数使用当前和目录建立可执行模块的路径。
这个参数可以被设为NULL,在这种情况下,可执行模块的名字必须处于 lpCommandLine 参数最前面并由与后面的字符分开。
lpCommandLine
指向一个以NULL结尾的字符串,该字符串指定要执行的命令行。
这个参数可以为空,那么函数将使用lpApplicationName参数指定的字符串当做要运行的程序的命令行。
如果lpApplicationName和lpCommandLine参数都不为空,那么lpApplicationName参数指定将要被运行的模块,lpCommandLine参数指定将被运行的模块的命令行。新运行的进程可以使用函数获得整个命令行。C语言程序可以使用argc和argv参数。
lpProcessAttributes
指向一个SECURITY_ATTRIBUTES结构体,这个决定是否返回的句柄可以被子进程继承。如果lpProcessAttributes参数为空(NULL),那么句柄不能被继承。
在Windows NT中:结构的lpSecurityDescriptor成员指定了新进程的,如果参数为空,新进程使用默认的安全描述符。
lpThreadAttributes
同lpProcessAttribute,不过这个参数决定的是线程是否被继承.通常置为NULL.
bInheritHandles
指示新进程是否从调用进程处继承了句柄。
如果参数的值为真,调用进程中的每一个可继承的打开句柄都将被子进程继承。被继承的句柄与原进程拥有完全相同的值和访问权限。
dwCreationFlags
指定附加的、用来控制优先类和进程的创建的标志。以下的创建标志可以以除下面列出的方式外的任何方式组合后指定。
⑴值:CREATE_DEFAULT_ERROR_MODE
含义:新的进程不继承调用进程的错误模式。CreateProcess函数赋予新进程当前的默认错误模式作为替代。应用程序可以调用函数设置当前的默认错误模式。
这个标志对于那些运行在没有硬件错误环境下的多线程是十分有用的。
对于CreateProcess函数,默认的行为是为新进程继承调用者的错误模式。设置这个标志以改变默认的处理方式。
⑵值:CREATE_NEW_CONSOLE
含义:新的进程将使用一个新的控制台,而不是继承的控制台。这个标志不能与DETACHED_PROCESS标志一起使用。
⑶值:CREATE_NEW_PROCESS_GROUP
含义:新进程将是一个的根进程。进程树中的全部进程都是根进程的子进程。新进程树的与这个进程的标识符是相同的,由lpProcessInformation参数返回。进程树经常使用GenerateConsoleCtrlEvent函数允许发送CTRL+C或CTRL+BREAK信号到一组控制台进程。
⑷值:CREATE_SEPARATE_WOW_VDM
如果被设置,新进程将会在一个私有的虚拟DOS机(VDM)中运行。另外,默认情况下所有的16位Windows应用程序都会在同一个共享的VDM中以的方式运行。单独运行一个16位程序的优点是一个应用程序的崩溃只会结束这一个VDM的运行;其他那些在不同VDM中运行的程序会继续正常的运行。同样的,在不同VDM中运行的16位Windows应用程序拥有不同的输入队列,这意味着如果一个程序暂时失去响应,在独立的VDM中的应用程序能够继续获得输入。
⑸值:CREATE_SHARED_WOW_VDM
如果WIN.INI中的Windows段的DefaultSeparateVDM选项被设置为真,这个标识使得CreateProcess函数越过这个选项并在共享的虚拟DOS机中运行新进程。
⑹值:CREATE_SUSPENDED
含义:新进程的会以暂停的状态被创建,直到调用函数被调用时才运行。
⑺值:CREATE_UNICODE_ENVIRONMENT
含义:如果被设置,由lpEnvironment参数指定的环境块使用Unicode,如果为空,环境块使用ANSI字符。
⑻值:DEBUG_PROCESS
含义:如果这个标志被设置,调用进程将被当做一个,并且新进程会被当做被调试的进程。系统把被调试程序发生的所有调试事件通知给调试器。
如果你使用这个标志创建进程,只有调用进程(调用CreateProcess函数的进程)可以调用函数。
⑼值:DEBUG_ONLY_THIS_PROCESS
含义:如果此标志没有被设置且调用进程正在被调试,新进程将成为调试调用进程的调试器的另一个调试对象。如果调用进程没有被调试,有关调试的行为就不会产生。
⑽值:DETACHED_PROCESS
含义:对于控制台进程,新进程没有访问控制台的权限。新进程可以通过函数自己创建一个新的控制台。这个标志不可以与CREATE_NEW_CONSOLE标志一起使用。
〔11〕值:CREATE_NO_WINDOW
含义:系统不为新进程创建CUI窗口,使用该标志可以创建不含窗口的CUI程序。
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
含义:指示这个进程拥有可用的最高优先级。一个拥有实时优先级的进程的可以打断所有其他进程线程的执行,包括正在执行重要任务的系统进程。例如,一个执行时间稍长一点的实时进程可能导致不足或鼠标反映迟钝。
lpEnvironment
指向一个新进程的环境块。如果此参数为空,新进程使用调用进程的环境。
一个环境块存在于一个由以NULL结尾的字符串组成的块中,这个块也是以NULL结尾的。每个字符串都是name=value的形式。
因为相等标志被当做,所以它不能被当做变量名。
与其使用应用程序提供的环境块,不如直接把这个参数设为空,系统驱动器上的当前目录信息不会被自动传递给新创建的进程。对于这个情况的探讨和如何处理,请参见注释一节。
环境块可以包含Unicode或ANSI字符。如果lpEnvironment指向的环境块包含Unicode,那么dwCreationFlags字段的CREATE_UNICODE_ENⅥRONMENT标志将被设置。如果块包含ANSI字符,该标志将被清空。
请注意一个ANSI环境块是由两个零字节结束的:一个是字符串的结尾,另一个用来结束这个快。一个Unicode环境块是由四个零字节结束的:两个代表字符串结束,另两个用来结束块。
lpCurrentDirectory
指向一个以NULL结尾的字符串,这个字符串用来指定子进程的。这个字符串必须是一个包含驱动器名的。如果这个参数为空,新进程将使用与调用进程相同的驱动器和目录。这个选项是一个需要启动应用程序并指定它们的驱动器和工作目录的的主要条件。
lpStartupInfo
指向一个用于决定新进程的主如何显示的。
lpProcessInformation
指向一个用来接收新进程的识别信息的结构体。
CreateProcess返回值
如果函数执行成功,返回非零值。
如果函数执行失败,返回零,可以使用GetLastError函数获得错误的附加信息。
CreateProcess注释:
CreateProcess函数用来运行一个新程序。和函数依旧可用,但是它们同样通过调用CreateProcess函数实现。
另外CreateProcess函数除了创建一个进程,还创建一个线程对象。这个线程将连同一个已初始化了的一起被创建,堆栈的大小由的中的描述决定。线程由文件头处开始执行。
新进程和新线程的句柄被以全局访问权限创建。对于这两个句柄中的任一个,如果没有,那么这个句柄就可以在任何需要句柄类型作为参数的函数中被使用。当提供安全描述符时,在接下来的时候当句柄被使用时,总是会先进行访问权限的检查,如果访问权限检查拒绝访问,请求的进程将不能使用这个句柄访问这个进程。
这个进程会被分配给一个32位的进程标识符。直到进程中止这个标识符都是有效的。它可以被用来标识这个进程,或在函数中被指定以打开这个进程的句柄。进程中被初始化了的线程一样会被分配一个32位的线程标识符。这个标识符直到线程中止都是有效的且可以用来在系统中唯一标识这个线程。这些标识符在中返回。
当在lpApplicationName或lpCommandLine参数中指定应用程序名时,应用程序名中是否包含扩展名都不会影响运行,只有一种情况例外:一个以.com为扩展名的MS-DOS程序或Windows程序必须包含.com扩展名。
调用进程可以通过函数来等待新进程完成它的初始化并等待用户输入。这对于和子进程之间的同步是极其有用的,因为CreateProcess函数不会等待新进程完成它的初始化工作。举例来说,在试图与新进程关联的窗口之前,进程应该先调用WaitForInputIdle。
首选的结束一个进程的方式是调用函数,因为这个函数通知这个进程的所有动态链接库(DLLs)程序已进入结束状态。其他的结束进程的方法不会通知关联的动态链接库。注意当一个进程调用ExitProcess时,这个进程的其他线程没有机会运行其他任何代码(包括关联动态链接库的终止代码)。
ExitProcess,,,,当一个进程启动时(调用了CreateProcess的结果)是在进程中序列化进行的。在一段地址空间中,同一时间内这些事件中只有一个可以发生。这意味着下面的限制将保留:
*在进程启动和DLL初始化阶段,新的可以被创建,但是直到进程的DLL初始化完成前它们都不能开始运行。
*在DLL初始化或卸下例程中进程中只能有一个线程。
*直到所有的线程都完成DLL初始化或卸下后,ExitProcess函数才返回。
在进程中的所有线程都终止且进程所有的句柄和它们的线程被通过调用函数终止前,进程会留在系统中。进程和的句柄都必须通过调用CloseHandle函数关闭。如果不再需要这些句柄,最好在创建进程后立刻关闭它们。
当进程中最后一个线程终止时,下列的事件发生:
*所有由进程打开的对象都会关闭。
*进程的终止状态(由函数返回)从它的初始值STILL_ACTⅣE变为最后一个结束的线程的结束状态。
*主线程的线程对象被设置为标志状态,供其他等待这个对象的使用。
*进程对象被设置为标志状态,供其他等待这个对象的线程使用。
假设当前在C盘上的目录是\MSVC\MFC且有一个叫做C:,它的值是C:\MSVC\MFC,就像前面lpEnvironment中提到过的那样,这样的系统驱动器上的目录信息在CreateProcess函数的lpEnvironment参数不为空时不会被自动传递到新进程里。一个应用程序必须手动地把当前目录信息传递到新的进程中。为了这样做,应用程序必须直接创建环境字符串,并把它们按字母顺序排列(因为Windows NT和Windows 95使用一种简略的环境变量),并把它们放进lpEnvironment中指定的环境块中。类似的,他们要找到环境块的开头,又要重复一次前面提到的环境块的排序。
一种获得驱动器X的当前目录变量的方法是调用("x:",..)。这避免了一个应用程序必须去扫描环境块。如果返回的是X:\,就不需要把这个值当作一个环境数据去传递了,因为根目录是驱动器X上的新进程的默认当前目录。
由CreateProcess函数返回的句柄对于进程对象具有PROCESS_ALL_ACCESS的访问权限。
由lpcurrentDirectory参数指定的当前目录室子进程对象的当前目录。lpCommandLine参数指定的第二个项目是的当前目录。
对于Windows NT,当一个进程在指定了CREATE_NEW_PROCESS_GROUP的情况下被创建时,一个对于SetConsoleCtrlHandler(NULL,True)的调用被用在新的进程上,这意味着对新进程来说CTRL+C是无效的。这使得上层的外科程序可以自己处理CTRL+C信息并有选择的把这些信号传递给子进程。CTRL+BREAK依旧有效,并可被用来中断进程/的执行。
CreateProcess安全注释:
第一个参数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中的第一个参数是一样的,有人说显得有些重复,其实这样做纯粹是一种被公认化了习惯!
CreateProcess参见
,,,,,,GenerateConsoleCtrlEvent,,,,,,,,,,,,SECURITY_ATTRIBUTES,,,,,,,
CreateProcess快捷信息:
:kernel32.lib
头文件:Winbase.h
CreateProcess举例说明
CreateProcessC代码
#include&stdio.h&
#include&windows.h&
intmain(intargc,char*argv[])
charszCommandLine[]="notepad";
STARTUPINFOsi={sizeof(si)};
PROCESS_INFORMATION
si.dwFlags=STARTF_USESHOWWINDOW;//指定wShowWindow成员有效
si.wShowWindow=TRUE;//此成员设为TRUE的话则显示新建进程的主窗口
BOOLbRet=CreateProcess(
NULL,//不在此指定可执行文件的文件名
szCommandLine,//命令行参数
NULL,//默认进程安全性
NULL,//默认进程安全性
FALSE,//指定当前进程内句柄不可以被子进程继承
CREATE_NEW_CONSOLE,//为新进程创建一个新的控制台窗口
NULL,//使用本进程的环境变量
NULL,//使用本进程的驱动器和目录
//不使用的句柄最好关掉
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
printf("新进程的ID号:%d\n",pi.dwProcessId);
printf("新进程的主线程ID号:%d\n",pi.dwThreadId);
CreateProcessC++代码
//不同的Windows系统notepad的路径可能会有出入,改一下路径即可(Win7x64亲测通过)
#include&iostream&
#include&stdlib.h&
#include&windows.h&
{//一些必备参数设置
STARTUPINFO
memset(&si,0,sizeof(STARTUPINFO));//初始化si在内存块中的值(详见memset函数)
si.cb=sizeof(STARTUPINFO);
si.dwFlags=STARTF_USESHOWWINDOW;
si.wShowWindow=SW_SHOW;
PROCESS_INFORMATION//必备参数设置结束
if(!CreateProcess(TEXT("c:\\windows\\system32\\notepad.exe"),
cout&&"CreateFail!"&&
cout&&"Success!"&&
//不使用的句柄最好关掉
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
//因为win7开始后更多的使用管理员权限,所以CreateProcessWithLogonW更多的被使用。同样的功能的还有
CreateProcessAsUser和CreateProcessWithTokenW。
//头文件添加略去了(includeWindows.h),配合管道读取回传值
//参考了MSDN相关条目,自行修改和DEBUG可用
BOOLCreateMyProcess(CStringstrCommand,DWORD&dwReturn,CString&strLog,CStringstrPwd){
dwReturn=-1;s
trLog=_T("");
//尝试登陆管理员账户
if(!LogonUserW(_T("Administrator"),
LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT,
intiError=GetLastError();
strLog.Format(_T("ErrorOnLogonUserW(),
errorcodeis%d."),
returnFALSE;
BOOLblResult=FALSE;
SECURITY_ATTRIBUTES
HANDLEhRead,hW
sa.nLength=sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor=NULL;
sa.bInheritHandle=TRUE;//创建管道
if(!CreatePipe(&hRead,&hWrite,&sa,0)){
strLog=_T("ErrorOnCreatePipe()");
returnFALSE;
STARTUPINFOsi={sizeof(si)};//将cb成员初始化为sizeof(si),其他成员初始化为0
::GetStartupInfo(&si);
si.hStdError=hW
si.hStdOutput=hW
si.wShowWindow=SW_HIDE;
si.dwFlags=STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
PROCESS_INFORMATION
CStringstrInfo=_T("");
ZeroMemory(&pi,sizeof(pi));//管理员方式启动进程
if(!CreateProcessWithLogonW(_T("Administrator"),NULL,strPwd,LOGON_WITH_PROFILE,NULL,strCommand.GetBuffer(),CREATE_UNICODE_ENVIRONMENT,NULL,NULL,&si,&pi)){
intiError=GetLastError();
strLog.Format(_T("ErrorOnCreateProcessWithLogonW(),errorcodeis%d."),iError);
CloseHandle(hWrite);
CloseHandle(hRead);
returnFALSE;}CloseHandle(hWrite);
charbuffer[4096]={0};
DWORDbytesRead=0;//读取回传值
while(true){
if(ReadFile(hRead,buffer,4095,&bytesRead,NULL)==NULL)//获取了回传值,处理回传值
Sleep(100);
}//资源清理
CloseHandle(hRead);
CloseHandle(hToken);
WaitForSingleObject(pi.hProcess,INFINITE);
GetExitCodeProcess(pi.hProcess,&dwReturn);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
returnTRUE;

我要回帖

更多关于 dll cstring 的文章

 

随机推荐