C++利用CerateProcess創建WPF進程并通過命名管道通訊

引言

原因是我需要在C++程序中調用另外一個WPF窗體打開或則關閉,進程之前通過通訊協議進行交互。由于使用不同語言開發,兩者都比較復雜不方便重寫,最方便的方法就是使用進程間通信,WPF窗體應用程序根據消息進行Show/Hide/Exit操作。

函數介紹CreateProcess

BOOL CreateProcess(LPCWSTR               lpApplicationName,//指向可執行模塊名稱的指針LPWSTR                lpCommandLine,//指向命令行字符串的指針。LPSECURITY_ATTRIBUTES lpProcessAttributes,//指向 SECURITY_ATTRIBUTES 結構的指針,指定新進程的安全屬性。LPSECURITY_ATTRIBUTES lpThreadAttributes,//指向 SECURITY_ATTRIBUTES 結構的指針,指定新線程的安全屬性。BOOL                  bInheritHandles,//如果為 TRUE,新進程將繼承調用進程的句柄。DWORD                 dwCreationFlags,//指定附加的、用來控制優先類和進程的創建的標志。LPVOID                lpEnvironment,//指向新進程的環境塊的指針。如果為 NULL,新進程將使用調用進程的環境。LPCWSTR               lpCurrentDirectory,//指向新進程的當前目錄的指針。如果為 NULL,新進程將使用調用進程的當前目錄。LPSTARTUPINFOW        lpStartupInfo,//指向 STARTUPINFOW 結構的指針,指定新進程的主窗口特性。LPPROCESS_INFORMATION lpProcessInformation//指向 PROCESS_INFORMATION 結構的指針,接收新進程的標識符和句柄。
);

1、lpApplicationName

即將啟動的exe程序路徑,該參數是一個字符串。我們可以傳相對路徑或者絕對路徑,Windows在啟動的時候,會按照一定的順序查找exe。

1、如果該參數傳遞的是exe全路徑,操作系統會直接啟動指定的全路徑exe,如果找不到要啟動的exe文件,CreateProcess會啟動失敗。

2、查找主進程exe同級目錄下是否存在要啟動的exe文件。

3、查詢主進程的當前目錄下是否存在要啟動的exe文件,一般情況下,主進程的當前目錄和主進程exe是同一個目錄,但是也不絕對,我們可以手動修改程序的當前目錄。

4、查詢Window系統目錄下是否存在要啟動的exe文件,就是GetSystemDirectory獲取到的文件夾。

5、查詢Window目錄下是否存在要啟動的exe文件。

6、查詢環境變量Path所表示的那些目錄下,數據存在要啟動的exe文件。

從上面的流程看,操作系統查找要指定的exe文件是一個很復雜的流程,所以如果條件允許,我們建議傳遞全路徑。如果不允許,也至少應該是將exe文件放到主進程exe的相對目錄下,這也是我經常采用的一種方式。

2、lpCommandLine

表示要啟動的進程需要接受的命令行參數。

3、lpProcessAttributes、lpThreadAttributes、bInheritHandles

這兩個參數代表子進程的進程安全屬性和線程安全屬性,都指向SECURITY_ATTRIBUTES的一個結構體,一般情況下,我們可以傳NULL,表示子進程使用默認的進程安全屬性和 線程安全屬性。bInheritHandles表示子進程是否可以繼承父進程的句柄(父進程設置了允許繼承的安全屬性)。如果設置為TRUE,則表示可以繼承。

4、dwCreationFlags

參數用于指定創建新進程的時候的一些附加標志,用于控制新進程的一些行為,下面是常用的一些標識:


1、CREATE_NEW_CONSOLE:為新進程創建一個新的控制臺窗口。上面的代碼我們使用了這個表示,主進程和新進程是兩個控制臺窗口,如果沒有這個flag的話,主進程和新創建的進程共用一個 控制臺程序。

2、CREATE_NO_WINDOW:不要為新進程啟動一個窗口。如果我們需要創建一個在后臺運行沒有界面的進程的話,可以使用這個flag。

3、CREATE_SUSPENDED:創建新進程,不要立即執行,將進程掛起,直到調用ResumeThread函數的時候,才開始調用進程。如果我們創建多個子進程之后,需要有一個統一的同步策略,由主進程統一控制多個子進程的執行順序的話,可以使用這個flag,在上面的代碼上稍微做一點修改,新增一個flag和新增兩行代碼,運行起來,你會發現新創建的進程不會立即執行,而是等待5s之后由主進程控制它繼續執行。

BOOL ret = CreateProcess(lpApplicationName,lpCommandLine,NULL,NULL,FALSE,CREATE_NEW_CONSOLE | CREATE_SUSPENDED,NULL,NULL,&si,&pi);

4、CREATE_UNICODE_ENVIRONMENT:創建Unicode字符的環境變量,如果使用了該flag,那么?lpEnvironment?參數指向的環境變量塊將使用Unicode,否則將使用ANSI字符。

5、CREATE_DEFAULT_ERROR_MODE:每個進程都有自己的一個錯誤模式,可以通過SetErrorMode?函數設置,默認情況下,新進程繼承父進程的錯誤模式,如果使用該flag,新進程將使用默認的錯誤模式。

6、DETACHED_PROCESS:新進程和父進程分離,不繼承父進程的控制臺。該flag會阻止子進程訪問父進程的控制臺窗口,一般我們也很少使用該flag。這個flag和CREATE_NO_WINDOW?作用一致,不能同時使用,否則程序會報錯。

5、lpEnvironment

默認情況下,子進程將繼承父進程的環境變量。如果想給子進程單獨設置環境變量塊,可以傳遞該參數。

6、lpCurrentDirectory

設置子進程的運行目錄,如果為 NULL,新進程將使用調用進程的當前目錄。當子進程有許多依賴項是務必要填入應用程序exe的絕對路徑。

7、lpStartupInfo

指定新進程的主窗體特性(指定窗體大小、初始位置、控制臺背景顏色字體顏色、窗口標題等信息)、標準輸入、輸出、錯誤設備句柄等

typedef struct _STARTUPINFOW {DWORD   cb;//結構的大小,以字節為單位。LPWSTR  lpReserved;//保留,必須為 NULL。LPWSTR  lpDesktop;//指向一個以空字符結尾的字符串,指定桌面名稱。LPWSTR  lpTitle;//指向一個以空字符結尾的字符串,指定新進程的窗口標題。DWORD   dwX;//指定窗口的初始位置XDWORD   dwY;//指定窗口的初始位置YDWORD   dwXSize;/指定窗口的初始大小XDWORD   dwYSize;//指定窗口的初始大小YDWORD   dwXCountChars;//指定屏幕緩沖區的寬度,以字符為單位。DWORD   dwYCountChars;//指定屏幕緩沖區的高度,以字符為單位。DWORD   dwFillAttribute;//指定新控制臺窗口的文本和背景顏色。DWORD   dwFlags;//指定有效的 STARTUPINFO 成員。WORD    wShowWindow;//指定窗口顯示狀態。WORD    cbReserved2;//保留,必須為 0。LPBYTE  lpReserved2;//保留,必須為 NULL。HANDLE  hStdInput;//新進程的標準輸入句柄HANDLE  hStdOutput;//新進程的標準輸出句柄HANDLE  hStdError;//新進程的標準錯誤設備句柄
} STARTUPINFOW, *LPSTARTUPINFOW;

8、lpProcessInformation

lpProcessInformation是一個輸出參數,進程創建之后,會把子進程的進程句柄、線程句柄、進程id、線程id返回給主進程。參數的定義如下:

typedef struct _PROCESS_INFORMATION {HANDLE hProcess;HANDLE hThread;DWORD dwProcessId;DWORD dwThreadId;
} PROCESS_INFORMATION, *PPROCESS_INFORMATION, *LPPROCESS_INFORMATION;

關于進程Id和線程Id需要注意的是:Windows有一個ID編號池,用于給進程和線程分配ID,并且這個ID池中的ID永遠不會重復,這意味著永遠不會有進程ID和線程ID重復。不過當進程線程推出的時候,這個進程的ID會回到ID池,后續可能會分配給別的進程。

試想一下。我用進程111創建了一個子進程222,子進程222的父進程確實是111,但是因為某些原因進程111被回收,并且重新分配給了一個其他的進程,如果這個時候,子進程再拿著父進程的ID:111去處理業務的話,就會出現意想不到的錯誤。同理,線程ID也是如此。所以,一般情況下,我們習慣用句柄操作具體業務,很少會使用ID來處理業務。那么hProcess參數和hThread參數就代表子進程的進程句柄和主線程句柄,父進程可以使用這兩個參數做對應的業務邏輯。

例子

#include <windows.h>
#include <iostream>
#include <string>
#include <tchar.h>
#include <thread>
bool SendCommandToWpf(const std::wstring& command)
{HANDLE hPipe;DWORD dwWritten;// 等待管道可用while (1){hPipe = CreateFile(TEXT("\\\\.\\pipe\\WpfConsoleCommunicationPipe"), // 管道名稱GENERIC_READ | GENERIC_WRITE,0,              // 不共享NULL,           // 默認安全屬性OPEN_EXISTING,  // 打開已存在的管道0,              // 默認屬性NULL);         // 不指定模板文件// 如果管道連接成功,退出循環if (hPipe != INVALID_HANDLE_VALUE)break;// 如果錯誤不是ERROR_PIPE_BUSY,則失敗if (GetLastError() != ERROR_PIPE_BUSY){std::cout << "無法打開管道. 錯誤代碼: " << GetLastError() << std::endl;return false;}// 所有管道實例都忙,等待20秒if (!WaitNamedPipe(TEXT("\\\\.\\pipe\\WpfConsoleCommunicationPipe"), 20000)){std::cout << "無法在20秒內連接管道." << std::endl;return false;}}// 管道連接成功,設置讀寫模式DWORD dwMode = PIPE_READMODE_MESSAGE;if (!SetNamedPipeHandleState(hPipe,    // 管道句柄&dwMode,  // 新的管道模式NULL,     // 不設置最大字節數NULL))    // 不設置最大超時時間{std::cout << "設置管道模式失敗. 錯誤代碼: " << GetLastError() << std::endl;CloseHandle(hPipe);return false;}// 發送命令if (!WriteFile(hPipe,                  // 管道句柄command.c_str(),       // 消息(command.size() + 1) * sizeof(wchar_t), // 消息長度(包含null終止符)&dwWritten,             // 實際寫入的字節數NULL))                  // 不重疊I/O{std::cout << "寫入管道失敗. 錯誤代碼: " << GetLastError() << std::endl;CloseHandle(hPipe);return false;}CloseHandle(hPipe);return true;
}void StartWpfApplication()
{STARTUPINFO si;PROCESS_INFORMATION pi;ZeroMemory(&si, sizeof(si));si.cb = sizeof(si);ZeroMemory(&pi, sizeof(pi));// 替換為你的WPF應用程序路徑std::wstring wpfAppPath = L"D:/程序代碼/WPF-Window.exe";std::wstring RunDir = L"D:/程序代碼/";if (!CreateProcess(&wpfAppPath[0],         // 應用程序名稱NULL,                   // 命令行NULL,                   // 進程安全屬性NULL,                   // 線程安全屬性FALSE,                  // 不繼承句柄REALTIME_PRIORITY_CLASS,// 創建新控制臺窗口以便查看輸出NULL,                   // 使用父進程環境塊&RunDir[0],             // 使用父進程起始目錄&si,                    // 啟動信息&pi))                   // 進程信息{std::cout << "創建進程失敗. 錯誤代碼: " << GetLastError() << std::endl;return;}// 關閉不需要的句柄CloseHandle(pi.hProcess);CloseHandle(pi.hThread);std::this_thread::sleep_for(std::chrono::seconds(10));//確保進行已啟動
}int main()
{// 啟動WPF應用程序StartWpfApplication();std::cout << "控制臺程序已啟動. 輸入命令(Show/Hide/Exit):" << std::endlstd::wstring command;while (std::getline(std::wcin, command)){if (command == L"Exit"){SendCommandToWpf(command);break;}else if (command == L"Show" || command == L"Hide"){if (!SendCommandToWpf(command)){std::cout << "發送命令失敗." << std::endl;}}else{std::cout << "未知命令. 可用命令: Show, Hide, Exit" << std::endl;}}return 0;
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/94212.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/94212.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/94212.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Seaborn數據可視化實戰

1. Seaborn基礎與實踐&#xff1a;數據可視化的藝術 2. Seaborn入門&#xff1a;環境搭建與基礎操作 3. Seaborn基礎圖表繪制入門 4. Seaborn數據可視化基礎&#xff1a;從內置數據集到外部數據集的應用 5. Seaborn顏色與樣式定制教程 6. Seaborn數據可視化入門&#xff1a;繪制…

BIM+寫實數字孿生落地實戰指南

&#x1f31f; 正文 在智慧城市與工業4.0的浪潮中&#xff0c;BIM與數字孿生的深度碰撞正在重塑建筑的生命周期。基于Revit&#xff08;RVT&#xff09;模型構建的超寫實數字孿生體&#xff0c;不僅實現物理空間的毫米級鏡像&#xff0c;更通過實時數據驅動&#xff0c;賦予建…

[Git] 如何拉取 GitHub 倉庫的特定子目錄

作為開發者&#xff0c;我們經常遇到只需要克隆大型倉庫中某個子目錄的場景。 Git 本身并不支持直接克隆子目錄&#xff0c;但通過一些技巧可以實現類似效果。本文將介紹幾種實用的方法&#xff0c;幫助獲取目標代碼。 為什么需要局部拉取&#xff1f; 節省時間和帶寬&#xff…

修復Simulink到UE5丟包時被控船體的殘影問題

提問 simulink 有一個和UE5協同的模塊&#xff0c;叫做Simulation 3D Scence Configuration&#xff0c;還有一個發送來自simulink到UE5數據的模塊叫做Simulation 3D Message。 現在遇到的問題是&#xff0c;這兩個模塊的優先級設置是正確的&#xff0c;且sample time都設置為0…

嵌入式第三十五課!!Linux下的網絡編程

一、目的網絡編程的目的實際上也是進程通信的一種方式&#xff0c;不過它可以在不同的主機上進行通信&#xff1b;二、需要解決的問題1. 主機與主機之間物理層面必須互聯互通。指的是參與通信的計算機&#xff08;主機&#xff09;需要通過物理設備建立連接&#xff08;光纖、網…

遙感機器學習入門實戰教程|Sklearn案例⑦:特征選擇與重要性分析

很多同學問&#xff1a;波段/特征一多就“維度災難”&#xff0c;訓練慢、過擬合&#xff0c;且很難解釋“哪些特征最關鍵”。本篇用 sklearn 給出一套能跑、可視化、可比較的最小工作流&#xff0c;并配上方法論速記&#xff0c;幫助你在高光譜/多特征任務里做出穩健篩選。 &a…

地理數據制備:蔚藍地圖空氣質量數據的獲取、清洗與坐標匹配指南

【&#x1f4ca;】手把手攻略&#xff1a;如何從“蔚藍地圖”挖寶——獲取濟南市可用空氣質量數據全記錄 一份不需要寫代碼也能搞定環境數據獲取的實用指南 ? 引言&#xff1a;為什么選擇蔚藍地圖&#xff1f; 作為一名環境數據愛好者&#xff0c;我經常需要獲取準確、可靠、…

Unreal Engine USceneComponent

Unreal&#x1f3db; Unreal Engine - USceneComponent&#x1f4da; 定義&#x1f3f7; 類繼承? 關鍵特性?? 常見配置&#x1f6e0;? 使用方法&#x1f517; 創建與掛載&#x1f504; 獲取與修改 Transform&#x1f9e9; 附加/分離組件&#x1f3ca; 典型應用場景&#x1…

2025年9月5090工作站、

在深度學習與大模型訓練領域&#xff0c;算力是決定研發效率與模型性能的核心要素&#xff0c;而顯卡作為算力輸出的核心硬件&#xff0c;其性能參數直接影響著訓練任務的速度、穩定性與成本控制。對于企業與科研機構而言&#xff0c;選擇一套適配自身需求且性價比優異的顯卡及…

亞矩陣云手機:亞馬遜第三方店鋪多賬號安全合規運營的核心技術支撐

亞矩陣云手機在亞馬遜第三方店鋪多賬號安全合規運營的技術支持&#xff0c;通過硬件級虛擬化、AI 行為建模、動態資源調度三大核心技術模塊&#xff0c;構建了覆蓋設備、網絡、行為、數據的四維防御體系&#xff0c;確保賬號在亞馬遜平臺規則下的長期穩定運行。以下從技術架構、…

使用C++11改進工廠方法模式:支持運行時配置的增強實現

在軟件開發中&#xff0c;工廠方法模式是一種常用的設計模式&#xff0c;用于創建對象。通過使用C11的新特性&#xff0c;我們可以進一步改進工廠方法模式&#xff0c;使其更加靈活和高效。本文將詳細介紹如何使用C11的std::function、lambda表達式和智能指針來實現一個支持運行…

小程序插件使用

插件介紹 插件是對一組 js 接口、自定義組件 或頁面的封裝&#xff0c;用于嵌入到小程序中使用。插件不能獨立運行&#xff0c;必須嵌入在其他小程序中才能被用戶使用&#xff1b;而第三方小程序在使用插件時&#xff0c;也無法看到插件的代碼。因此&#xff0c;插件適合用來封…

要區分一張圖片中的網狀圖(如網格結構或規則紋理)和噪點(隨機分布的干擾像素),比如電路的方法 計算機視覺

要區分一張圖片中的網狀圖&#xff08;如網格結構或規則紋理&#xff09;和噪點&#xff08;隨機分布的干擾像素&#xff09;&#xff0c;需結合圖像預處理、特征提取和分割算法。以下是系統化的解決方案&#xff0c;分階段說明關鍵技術和算法選擇&#xff1a; &#x1f50d; 一…

06_并發編程高級特性

第6課:并發編程高級特性 課程目標 掌握context包的使用 理解sync包中的同步原語 學會處理并發安全問題 掌握性能優化技巧 1. Context包 1.1 Context基礎 import ("context""fmt""time" )// 基本Context使用 func basicContext()

X00238-非GNSS無人機RGB圖像衛星圖像視覺定位python

獲取方式見文末&#xff0c;可開發票隨著無人機在工業和科研領域應用的加速發展&#xff0c;在非城市環境中使用無gnss、基于視覺的方法進行無人機定位的需求日益增長。本文提出了一種基于視覺的定位算法&#xff0c;利用深度特征計算無人機在野外飛行的地理坐標。該方法基于匹…

Eino 開源框架全景解析 - 以“大模型應用的搭積木指南”方式理解

Eino 開源框架全景解析 - 大模型應用的搭積木指南 &#x1f3af; 什么是 Eino&#xff1f;一句話概括 Eino 是字節跳動開源的大語言模型應用開發框架&#xff0c;就像是一個專門為 AI 應用設計的"搭積木工具箱"&#xff0c;讓開發者能夠像搭樂高一樣輕松構建復雜的 A…

嵌入式開發中,usb通信中輸出端點和輸入端點

一. 簡介本文簡單學習一下&#xff0c;嵌入式開發中&#xff0c;usb的輸出端點和輸入端點。在嵌入式開發的 USB 通信場景中&#xff0c;輸出端點&#xff08;OUT Endpoint&#xff09; 和 輸入端點&#xff08;IN Endpoint&#xff09; 是 USB 設備與主機&#xff08;如電腦、嵌…

【自用】Maven常用依賴

【自用】Maven常用依賴 工具類 Guava Guava&#xff08;Google Guava&#xff09;是由Google團隊開發的一套Java開源工具庫&#xff0c;旨在簡化和增強Java開發者的日常工作。它提供了許多實用的工具和基礎設施&#xff0c;覆蓋了集合、并發、字符串處理、I/O、數學運算等多個…

Java 18 新特性及具體應用

目錄 1. UTF-8 默認編碼 (JEP 400) 2. 簡單 Web 服務器 (JEP 408) 3. Javadoc 代碼片段 (JEP 413) 4. switch 模式匹配 (JEP 420, 第二次預覽) 5. 向量 API (JEP 417, 第三次孵化) 總結 Java 18 于 2022 年 3 月發布&#xff0c;引入了多項新特性&#xff0c;旨在提升開發…

unistd.h 常用函數速查表

在這篇文章中&#xff0c;我們將整理一份 unistd.h 常用函數速查表&#xff0c;便于快速查找和記憶&#xff0c;涵蓋文件 I/O、進程管理、系統信息、用戶/組信息等方面。unistd.h 常用函數速查表&#xff08;POSIX/Linux/macOS&#xff09; 1. 文件與 I/O 操作函數說明示例int …