TypePHP 编译器 https://swoole.com/aot/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

238 lines
5.9 KiB

# 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
<?php
function main()
{
date_default_timezone_set('Asia/Shanghai');
// 欢迎消息
messagebox(0,
"欢迎使用!\n\n" .
"当前时间: " . date('Y-m-d H:i:s'),
"Hello",
0);
}
```
### 带错误处理的程序
```php
<?php
function main()
{
date_default_timezone_set('Asia/Shanghai');
try {
// 你的业务逻辑
$result = someOperation();
messagebox(0, "操作成功!结果: " . $result, "成功", 64); // MB_ICONINFORMATION
} catch (\Exception $e) {
messagebox(0, "发生错误:\n" . $e->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)