能否将Python脚本转成exe后用C++调用并传递变量?
Let's walk through exactly how to tackle this—since you're building a DLL for ZBrush and need to avoid forcing users to install Python, we'll split this into two core parts: packaging your Python script into a standalone EXE, and then invoking that EXE from your C++ DLL with parameters.
1. Package Your Python Script into a Standalone EXE
We'll use PyInstaller here (it’s more reliable for single-file builds and handles modern Python dependencies better than py2exe).
First, set up your Python script to accept command-line arguments—this is how your C++ code will pass data to it:
# your_script.py import sys def main(): # Access parameters passed from C++ via sys.argv (index 0 is the script name itself) if len(sys.argv) < 2: print("No input parameters provided") return # Extract parameters (adjust based on how many you need) first_param = sys.argv[1] second_param = sys.argv[2] if len(sys.argv) > 2 else "" # Your core script logic here using the parameters print(f"Processing: {first_param} with setting {second_param}") if __name__ == "__main__": main()
Next, run PyInstaller to bundle the script into a single, self-contained EXE:
pyinstaller --onefile --noconsole your_script.py
--onefilepacks everything (Python interpreter, dependencies, script) into a single executable—super easy to distribute.--noconsolehides the command prompt window, which is critical for ZBrush integration (users don’t want random popups while working).
Grab the finished EXE from the dist folder—this is the file you’ll ship alongside your C++ DLL.
2. Call the EXE from Your C++ DLL
Since you’re building a Windows DLL for ZBrush, use the Windows API’s CreateProcess function—it gives you precise control over the process execution, which is better than ShellExecute for this use case.
Here’s a reusable code snippet to invoke the EXE and pass parameters:
#include <windows.h> #include <string> #include <iostream> bool RunPythonExe(const std::string& exePath, const std::string& params) { // Wrap the EXE path in quotes to handle spaces in file paths std::string fullCommand = "\"" + exePath + "\" " + params; STARTUPINFO si = {0}; PROCESS_INFORMATION pi = {0}; si.cb = sizeof(STARTUPINFO); // Launch the EXE process if (!CreateProcessA( NULL, // Use command line instead of module path (LPSTR)fullCommand.c_str(),// Full command line (EXE + params) NULL, // Don't inherit process handle NULL, // Don't inherit thread handle FALSE, // Disable handle inheritance 0, // No special creation flags NULL, // Use parent environment variables NULL, // Use parent working directory &si, // Startup info structure &pi // Process info structure )) { // Handle errors (log to ZBrush's console or return failure) DWORD errorCode = GetLastError(); std::cerr << "Failed to launch EXE. Error code: " << errorCode << std::endl; return false; } // Optional: Wait for the Python script to finish executing // Remove this if you want the DLL to continue without waiting WaitForSingleObject(pi.hProcess, INFINITE); // Clean up process handles CloseHandle(pi.hProcess); CloseHandle(pi.hThread); return true; } // Example usage in your ZBrush DLL function void YourZBrushPluginFunction() { // Get the DLL's directory to locate the EXE (avoids hardcoding paths) char dllDir[MAX_PATH]; GetModuleFileNameA(NULL, dllDir, MAX_PATH); std::string exePath(dllDir); exePath = exePath.substr(0, exePath.find_last_of("\\/")) + "\\your_script.exe"; // Pass parameters to the EXE (space-separated, wrap in quotes if params have spaces) std::string inputParams = "high_res_model 2048"; RunPythonExe(exePath, inputParams); }
Key Tips for Success:
- Path Safety: Always use
GetModuleFileNameto find your DLL’s location, then build the EXE path relative to it—this prevents broken paths if users install your plugin in a non-default folder. - Parameter Format: Separate parameters with spaces. If a parameter contains spaces (like a file path), wrap it in double quotes (e.g.,
"C:/My Models/sphere.obj"). - Error Handling: Add logging or feedback for failed process launches—ZBrush has its own console system you can use to notify users of issues.
- Async Execution: If you don’t need to wait for the Python script to finish, remove the
WaitForSingleObjectcall—just remember to still close the process and thread handles to avoid resource leaks.
内容的提问来源于stack exchange,提问作者thedean91

