# Windows GUI 程序指南 ## 概述 本示例展示了如何使用 PHPX 编译器创建纯图形界面的 Windows 程序,不显示控制台窗口。 ## 关键特性 ### 1. 隐藏控制台窗口 通过添加 `--no-console` 编译参数,程序将以 Windows 子系统模式运行,不会显示黑色的控制台终端窗口。 **使用方法:** ```bash php cli.php build --mode=bin --no-console your-app.php ``` **实现位置:** - 选项定义:`src/Php/Constants.php` - 参数读取:`src/Php/Translator.php` - 链接配置:`src/Php/CompilerBase.php` ```php // 对于 bin 模式且指定了 --no-console,使用 Windows 子系统(不显示控制台窗口) if ($this->buildMode === 'bin' && $this->noConsole) { $cmd .= ' /SUBSYSTEM:WINDOWS'; } ``` ### 2. 中文支持 #### C++ 层(消息框) 在 C++ 中使用 `MultiByteToWideChar` 将 UTF-8 转换为 UTF-16,然后调用 `MessageBoxW`: ```cpp // Convert UTF-8 to UTF-16 for Windows API int wtext_len = MultiByteToWideChar(CP_UTF8, 0, text.data(), -1, NULL, 0); wchar_t* wtext = new wchar_t[wtext_len]; MultiByteToWideChar(CP_UTF8, 0, text.data(), -1, wtext, wtext_len); int result = MessageBoxW((HWND)hWnd, wtext, wcaption, (UINT)uType); delete[] wtext; delete[] wcaption; ``` #### PHP 层(时区设置) ```php // Set timezone to China (UTC+8) date_default_timezone_set('Asia/Shanghai'); ``` ### 3. 输出方式 由于没有控制台窗口,所有输出必须通过 GUI 元素显示: - **消息框**:使用 `messagebox()` 或 `MessageBox()` 函数 - **自定义窗口**:需要实现完整的窗口类和消息循环 - **日志文件**:可以写入文件进行调试 ## 编译和运行 ### 带控制台窗口(默认) ```bash # 进入示例目录 cd examples/win32-hello # 编译为带控制台的程序(默认) php ../../cli.php build --mode=bin hello-win.php # 运行程序(显示控制台和消息框) .\hello-win.exe ``` ### 不带控制台窗口(GUI 模式) ```bash # 使用 --no-console 参数编译纯 GUI 程序 php ../../cli.php build --mode=bin --no-console hello-win.php # 运行程序(只显示消息框,无控制台) .\hello-win.exe ``` ## 注意事项 ### ⚠️ 重要限制 1. **没有标准输入输出** - `echo`、`print`、`printf` 等控制台输出函数无效 - `stdin`、`stdout`、`stderr` 不可用 - 所有输出必须通过 GUI 元素 2. **调试困难** - 无法在控制台查看调试信息 - 建议使用: - 消息框显示调试信息 - 写入日志文件 - 使用 Visual Studio 调试器附加进程 3. **入口点要求** - 使用 `/SUBSYSTEM:WINDOWS` 后,默认入口点是 `WinMain` 而不是 `main` - PHPX 编译器会自动处理这个转换 ### ✅ 最佳实践 1. **使用消息框进行用户交互** ```php messagebox(0, "操作成功!", "提示", 0); ``` 2. **错误处理** ```php try { // 你的代码 } catch (\Exception $e) { messagebox(0, "错误: " . $e->getMessage(), "错误", 16); // MB_ICONERROR } ``` 3. **日志记录** ```php file_put_contents('app.log', date('Y-m-d H:i:s') . ": 消息\n", FILE_APPEND); ``` ## 两种模式对比 | 特性 | 控制台模式 (默认) | 窗口模式 (`--no-console`) | |------|------------------|-------------------------| | 编译命令 | `php cli.php build app.php` | `php cli.php build --no-console app.php` | | 链接选项 | `/SUBSYSTEM:CONSOLE` | `/SUBSYSTEM:WINDOWS` | | 控制台窗口 | ✅ 显示 | ❌ 隐藏 | | echo/print | ✅ 可用 | ❌ 不可用 | | stdin/stdout | ✅ 可用 | ❌ 不可用 | | 消息框 | ✅ 可用 | ✅ 可用 | | 适用场景 | 命令行工具、调试 | GUI 应用程序 | | 用户体验 | 黑色终端窗口 | 纯图形界面 | ## 切换模式 ### 开发时(带控制台,便于调试) ```bash # 默认编译,显示控制台 php cli.php build --mode=bin app.php ``` ### 发布时(不带控制台,纯 GUI) ```bash # 使用 --no-console 参数 php cli.php build --mode=bin --no-console app.php ``` ### 在 project.yml 中配置 ```yaml build: mode: bin no_console: true # 隐藏控制台窗口 ``` ## 常见问题 ### Q: 为什么我的 echo 不显示? A: 因为使用了 `/SUBSYSTEM:WINDOWS`,控制台被隐藏了。请改用消息框或其他 GUI 元素。 ### Q: 如何调试没有控制台的程序? A: 1. 使用消息框显示变量值 2. 写入日志文件 3. 使用 Visual Studio 的"附加到进程"功能 4. 临时切换回控制台模式进行调试 ### Q: 可以同时显示控制台和窗口吗? A: 技术上可以,但不推荐。通常的做法是: - 开发时使用控制台模式便于调试 - 发布时使用窗口模式提供更好的用户体验 ### Q: 中文显示乱码怎么办? A: 确保: 1. C++ 文件使用 UTF-8 编码保存 2. 使用 `MultiByteToWideChar` 转换编码 3. 使用 `MessageBoxW` 而不是 `MessageBoxA` 4. 在 PHP 中设置正确的时区 ## 示例代码 ### 简单的消息框程序 ```php getMessage(), "错误", 16); // MB_ICONERROR } } ``` ## 相关资源 - [Windows Subsystem 文档](https://docs.microsoft.com/en-us/cpp/build/reference/subsystem-specify-subsystem) - [MessageBoxW API](https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-messageboxw) - [MultiByteToWideChar](https://docs.microsoft.com/en-us/windows/win32/api/stringapiset/nf-stringapiset-multibytetowidechar)