zl程序教程

您现在的位置是:首页 >  后端

当前栏目

C/C++ Windows API——执行进程

2023-09-11 14:22:54 时间
// ProcessDemo.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <Windows.h>

#pragma comment(lib, "urlmon.lib")//URLDownloadToFile

int main()
{
    BOOL ret;

    /*
    简单地执行程序
    __drv_preferredFunction("CreateProcess","Deprecated. See MSDN for details")
    WINBASEAPI UINT WINAPI WinExec(
        _In_ LPCTSTR lpCmdLine, //指向一个可执行的文件
        _In_ UINT uCmdShow      //窗口的初始显示方式,如果是SW_HIDE就不会显示直接在后台运行
    );

    uCmdShow可以是如下参数
    #define SW_HIDE             0
    #define SW_SHOWNORMAL       1   与SW_RESTORE相同
    #define SW_NORMAL           1
    #define SW_SHOWMINIMIZED    2
    #define SW_SHOWMAXIMIZED    3
    #define SW_MAXIMIZE         3
    #define SW_SHOWNOACTIVATE   4   用最近的大小和位置显示一个窗口,同时不改变活动窗口
    #define SW_SHOW             5   用当前的大小和位置显示一个窗口,同时令其进入活动状态
    #define SW_MINIMIZE         6
    #define SW_SHOWMINNOACTIVE  7
    #define SW_SHOWNA           8   用当前的大小和位置显示一个窗口,不改变活动窗口
    #define SW_RESTORE          9   用原来的大小和位置显示一个窗口,同时令其进入活动状态
    #define SW_SHOWDEFAULT      10
    #define SW_FORCEMINIMIZE    11
    #define SW_MAX              11

    若函数调用成功,则返回值大于31。若函数调用失败,则常见的返回值为下列之一:
    等于 0 {内存不足. 系统内存或资源已耗尽}
    ERROR_FILE_NOT_FOUND = 2; {文件名错误}
    ERROR_PATH_NOT_FOUND = 3; {路径名错误}
    ERROR_BAD_FORMAT = 11; {EXE 文件无效(非Win32.EXE或.EXE影像错误)}
    */
    LPCSTR lpCmdLine = "notepad.exe";
    UINT uCmdShow = SW_SHOW;
    UINT winExecRet = WinExec(lpCmdLine, uCmdShow);
    if (winExecRet > 31) {
        printf("WinExec -> succ, ret=%d\n", winExecRet);
    }
    else {
        printf("WinExec -> fail(%d), ret=%ld\n", GetLastError(), winExecRet);
    }

    /*
    #define STDAPI                  EXTERN_C HRESULT STDAPICALLTYPE
    STDAPI URLDownloadToFileW(
        _In_opt_ LPUNKNOWN pCaller,     //控件的接口,如果不是控件则为0.
        _In_ LPCTSTR szURL,             //要下载的url地址,不能为空.
        _In_opt_ LPCTSTR szFileName,    //下载后保存的文件名.
        DWORD dwReserved,               //保留字段,必需为0
        _In_opt_ LPBINDSTATUSCALLBACK lpfnCB    //下载进度状态回调
    );
    //小心!URLDownloadToFile不支持gzip压缩,如果网站使用了gzip压缩,你会很惨的。
    return
    #define S_OK                                   ((HRESULT)0L)
    #define S_FALSE                                ((HRESULT)1L)
    */
    LPUNKNOWN pCaller = NULL;
    LPCTSTR szURL = _T("http://www.baidu.com");
    LPCTSTR szFileName = _T("C:\\Users\\chenjia2014\\Desktop\\process_demo.html");
    DWORD dwReserved = 0;
    LPBINDSTATUSCALLBACK lpfnCB = NULL;
    /*
    Severity    Code    Description Project File    Line    Suppression State
    Error   LNK2019 unresolved external symbol _URLDownloadToFileW@20 referenced in function _main  ProcessDemo C : \Users\chenjia2014\Desktop\temp\vc\ProcessDemo\ProcessDemo\ProcessDemo.obj  1
    2019错误是找到头文件但没有找到实现的lib文件
    */
    HRESULT hResult = URLDownloadToFile(pCaller, szURL, szFileName, dwReserved, lpfnCB);
    if (hResult == S_OK) {
        printf("URLDownloadToFile -> %d -> S_OK\n", hResult);
    }
    else {
        printf("URLDownloadToFile -> %d -> not S_OK\n", hResult);
    }
    //这两种判断方式都是一样的
    if (SUCCEEDED(hResult)) {
        printf("URLDownloadToFile -> %d -> SUCCEEDED\n");
    }
    else if (FAILED(hResult)) {
        printf("URLDownloadToFile -> %d -> FAILED\n");
    }
    else {
        printf("URLDownloadToFile -> %d -> UNKNOWN\n");
    }

    /*
    WINBASEAPI BOOL WINAPI CreateProcess(
        _In_opt_ LPCTSTR lpApplicationName,                 //注意:这里的文件名一定要是路径全程,光用path中定义目录下的程序名是找不到的
        _Inout_opt_ LPTSTR lpCommandLine,                   //指的是传递给程序的参数
        _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, //指向一个SECURITY_ATTRIBUTES结构体,这个结构体决定是否返回的句柄可以被子进程继承。如果lpProcessAttributes参数为空(NULL),那么句柄不能被继承。
        _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,  //指向一个SECURITY_ATTRIBUTES结构体,这个结构体决定是否返回的句柄可以被子进程继承。如果lpThreadAttributes参数为空(NULL),那么句柄不能被继承。
        _In_ BOOL bInheritHandles,                          //指示新进程是否从调用进程处继承了句柄。如果参数的值为真,调用进程中的每一个可继承的打开句柄都将被子进程继承。被继承的句柄与原进程拥有完全相同的值和访问权限。
        _In_ DWORD dwCreationFlags,                         //指定附加的、用来控制优先类和进程的创建的标志。
        _In_opt_ LPVOID lpEnvironment,                      //指向一个新进程的环境块。如果此参数为空,新进程使用调用进程的环境。其间的每个字符都是name=value的形式
        //注意一个ANSI环境块是由两个零字节结束的:一个是字符串的结尾,另一个用来结束这个快。一个Unicode环境块石油四个零字节结束的:两个代表字符串结束,另两个用来结束块。
        _In_opt_ LPCTSTR lpCurrentDirectory,                //这个字符串用来指定子进程的工作路径。这个字符串必须是一个包含驱动器名的绝对路径。如果这个参数为空,新进程将使用与调用进程相同的驱动器和目录。
        _In_ LPSTARTUPINFOW lpStartupInfo,                  //指向一个用于决定新进程的主窗体如何显示的STARTUPINFO结构体。
        _Out_ LPPROCESS_INFORMATION lpProcessInformation    //成功返回非0,失败返回0。使用GetLastError函数获得错误的附加信息。
    );

    lpStartupInfo的dwFlags可以是如下参数
    // Dual Mode API below this line. Dual Mode Structures also included.
    #define STARTF_USESHOWWINDOW       0x00000001
    #define STARTF_USESIZE             0x00000002
    #define STARTF_USEPOSITION         0x00000004
    #define STARTF_USECOUNTCHARS       0x00000008
    #define STARTF_USEFILLATTRIBUTE    0x00000010
    #define STARTF_RUNFULLSCREEN       0x00000020  // ignored for non-x86 platforms
    #define STARTF_FORCEONFEEDBACK     0x00000040
    #define STARTF_FORCEOFFFEEDBACK    0x00000080
    #define STARTF_USESTDHANDLES       0x00000100
    #if(WINVER >= 0x0400)
    #define STARTF_USEHOTKEY           0x00000200
    #define STARTF_TITLEISLINKNAME     0x00000800
    #define STARTF_TITLEISAPPID        0x00001000
    #define STARTF_PREVENTPINNING      0x00002000
    */
    LPCTSTR lpApplicationName = _T("C:\\Windows\\system32\\calc.exe");
    LPTSTR lpCommandLine = NULL;
    LPSECURITY_ATTRIBUTES lpProcessAttributes = NULL;
    LPSECURITY_ATTRIBUTES lpThreadAttributes = NULL;
    BOOL bInheritHandles = FALSE;
    DWORD dwCreationFlags = 0;
    LPVOID lpEnvironment = NULL;
    LPCTSTR lpCurrentDirectory = NULL;
    STARTUPINFOW startupInfo = { 0 };
    startupInfo.cb = sizeof(STARTUPINFO);
    startupInfo.dwFlags = STARTF_USESHOWWINDOW;
    PROCESS_INFORMATION processInformation = { 0 };
    ret = CreateProcess(lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory, &startupInfo, &processInformation);
    if(ret) {
        printf("CreateProcess -> %d -> succ\n", ret);
        ret = CloseHandle(processInformation.hThread);
        if (ret) {
            printf("CloseHandle processInformation.hProcess -> %d -> succ\n", ret);
        }
        else {
            printf("CloseHandle processInformation.hProcess -> %d -> fail(%ld)\n", ret, GetLastError());
        }
        ret = CloseHandle(processInformation.hProcess);
        if (ret) {
            printf("CloseHandle processInformation.hProcess -> %d -> succ\n", ret);
        }
        else {
            printf("CloseHandle processInformation.hProcess -> %d -> fail(%ld)\n", ret, GetLastError());
        }
    }
    else {
        printf("CreateProcess -> %d -> fail(%ld)\n", ret, GetLastError());
    }

    /*
    ShellExecute解析系统注册表HKEY_CLASSES_ROOT中所有的内容,判断启动那一个执行程序,并且启动一个新的实例或使用DDE将文件名连到一打开的实例。然后,ShellExecute 返回打开文件的应用的实例句柄。
    SHSTDAPI_(HINSTANCE) ShellExecute(
        _In_opt_ HWND hwnd,             //用于指定父窗口句柄。当函数调用过程出现错误时,它将作为Windows消息窗口的父窗口,可以为NULL
        _In_opt_ LPCTSTR lpOperation,   //用于指定要进行的操作(open:打开程序或文件或文件夹、print:打印文件、explore:浏览文件夹),当参数为NULL时,默认执行open
        _In_ LPCTSTR lpFile,            //用于指定要打开的文件名,要执行程序的文件名,或要浏览的文件夹名,或网址,或邮件链接
        _In_opt_ LPCTSTR lpParameters,  //若lpFile参数是一个可执行程序,则此参数指定命令行参数,否则此参数应为NULL
        _In_opt_ LPCTSTR lpDirectory,   //用于指定默认目录
        _In_ INT nShowCmd               //若lpFile参数是一个可执行程序,则此参数指定程序窗口的初始显示方式,否则此参数应设置为0
    );
    */
    HWND hwnd = NULL;
    LPCTSTR lpOperation = _T("open");
    LPCTSTR lpFile = _T("http://www.baidu.com");
    //LPCTSTR lpFile = _T("mailto:1543289981@qq.com");
    LPCTSTR lpParameters = NULL;
    LPCTSTR lpDirectory = NULL;
    int nShowCmd = SW_SHOWNORMAL;
    /*
    程序的实例是一个正在运行的程序的信息,这样的信息很多,需要有一个代表
    早期windows没有完整的进程支持,所有任务共用地址空间,此时程序映像基地址就是一个不错的代表实例的东西
    现在windows有了完整的进程,地址空间隔离了,于是映像基地址就不再具有代表实例的价值,但hinstance这个名字还是传了下来,现在一般用pid代表实例
    */
    HINSTANCE hInstance = ShellExecute(NULL, lpOperation, lpFile, lpParameters, lpDirectory, nShowCmd);
    printf("ShellExecute -> %d\n", hInstance);

    /*
    _Check_return_ WINOLEAPI CoInitializeEx(
        _In_opt_ LPVOID pvReserved,
        _In_ DWORD dwCoInit
    );
    */
    LPVOID pvReserved = NULL;
    DWORD dwCoInit = COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE;
    hResult = CoInitializeEx(pvReserved, dwCoInit);
    printf("CoInitializeEx -> %d\n", hResult);

    /*
    typedef struct _SHELLEXECUTEINFOW
    {
        DWORD cbSize;               // in, required, sizeof of this structure
        ULONG fMask;                // in, SEE_MASK_XXX values
        HWND hwnd;                  // in, optional
        LPCWSTR  lpVerb;            // in, optional when unspecified the default verb is choosen
        LPCWSTR  lpFile;            // in, either this value or lpIDList must be specified
        LPCWSTR  lpParameters;      // in, optional
        LPCWSTR  lpDirectory;       // in, optional
        int nShow;                  // in, required
        HINSTANCE hInstApp;         // out when SEE_MASK_NOCLOSEPROCESS is specified
        void *lpIDList;             // in, valid when SEE_MASK_IDLIST is specified, PCIDLIST_ABSOLUTE, for use with SEE_MASK_IDLIST & SEE_MASK_INVOKEIDLIST
        LPCWSTR  lpClass;           // in, valid when SEE_MASK_CLASSNAME is specified
        HKEY hkeyClass;             // in, valid when SEE_MASK_CLASSKEY is specified
        DWORD dwHotKey;             // in, valid when SEE_MASK_HOTKEY is specified
        union                       
        {                           
            HANDLE hIcon;           // not used
    #if (NTDDI_VERSION >= NTDDI_WIN2K)
            HANDLE hMonitor;        // in, valid when SEE_MASK_HMONITOR specified
    #endif // (NTDDI_VERSION >= NTDDI_WIN2K)
        } DUMMYUNIONNAME;           
        HANDLE hProcess;            // out, valid when SEE_MASK_NOCLOSEPROCESS specified
    } SHELLEXECUTEINFOW, *LPSHELLEXECUTEINFOW;
    */
    SHELLEXECUTEINFO shellExecuteInfo = { 0 };
    shellExecuteInfo.cbSize = sizeof(SHELLEXECUTEINFO);
    shellExecuteInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
    shellExecuteInfo.lpFile = _T("mspaint.exe");
    shellExecuteInfo.lpParameters = NULL;
    shellExecuteInfo.lpDirectory = NULL;
    shellExecuteInfo.nShow = SW_SHOW;

    /*
    SHSTDAPI_(BOOL) ShellExecuteExW(_Inout_ SHELLEXECUTEINFOW *pExecInfo);
    如果函数成功执行就返回TRUE,否则返回 FALSE 。可调用 GetLastError 获取错误信息。

    由于ShellExecuteEx 能够将执行委托给那些由组件对象模型COM激活的Shell 扩展(数据源,上下文菜单句柄,动词实现),因此在调用ShellExecuteEx 之前要先初始化 COM。某些Shell 扩展要求单线程单元模型的COM
    在某些情况下 ShellExecuteEx 并没有使用这种类型的Shell 扩展,这时就无需初始化COM。虽然如此,总是在使用这个函数之前初始化COM是个不错的举措。
    */
    hResult = ShellExecuteEx(&shellExecuteInfo);
    if (hResult) {
        printf("ShellExecuteEx -> succ\n");

        HANDLE hProcess = shellExecuteInfo.hProcess;
        if (hProcess != 0) {
            WORD wEvent = WaitForSingleObject(hProcess, INFINITE);
            printf("WaitForSingleObject -> event=%d\n", wEvent);
            ret = CloseHandle(hProcess);
            printf("CloseHandle -> %d\n", ret);
        }
    }
    else {
        printf("ShellExecuteEx -> fail(%ld)\n", GetLastError());
    }

    CoUninitialize();
    system("pause");
    return 0;
}