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.
 
 

340 lines
8.6 KiB

# Win32 Hello World 示例
这个示例展示了如何使用 PHPX 编译器创建 Windows 程序,包括两种模式:
## 📁 示例文件
### 1. hello-console.php - 控制台版本(默认)
**特点:**
- ✅ 显示黑色控制台窗口
- ✅ 可以使用 `echo`、`print` 等控制台输出
- ✅ 可以显示消息框
- ✅ 适合命令行工具和调试
**编译命令:**
```bash
php ../../cli.php build --mode=bin hello-console.php
```
**运行效果:**
- 显示控制台窗口
- 输出文本信息到控制台
- 弹出消息框
---
### 2. hello-gui.php - GUI 版本(无控制台)
**特点:**
- ❌ 不显示控制台窗口
-`echo`、`print` 等控制台输出无效
- ✅ 只显示消息框等 GUI 元素
- ✅ 适合纯图形界面应用程序
**编译命令:**
```bash
php ../../cli.php build --mode=bin --no-console hello-gui.php
```
**运行效果:**
- 没有控制台窗口
- 直接弹出消息框
- 纯图形界面体验
---
### 3. debug-test.php - 调试测试程序
**特点:**
- ✅ 包含详细的日志记录
- ✅ 异常处理
- ✅ 逐步验证功能
- ✅ 用于排查 "Debug Assertion Failed" 问题
**编译命令:**
```bash
php ../../cli.php build --mode=bin --no-console debug-test.php
```
**使用方法:**
1. 编译并运行程序
2. 查看生成的 `debug-test.log` 文件
3. 根据日志定位问题
---
### 4. asan-test.php - AddressSanitizer 测试程序
**特点:**
- ✅ 演示 AddressSanitizer 的使用
- ✅ 包含各种内存操作测试
- ✅ 检测内存错误和泄漏
**编译命令:**
```bash
# Windows
php ../../cli.php build --mode=bin --sanitize=address --no-console asan-test.php
# Linux/macOS
php ../../cli.php build --mode=bin --sanitize=address,undefined asan-test.php
```
**使用方法:**
1. 编译带 sanitizer 的版本
2. 运行程序
3. 查看 `asan-test.log` 和控制台输出
4. 如果有内存错误,AddressSanitizer 会报告详细信息
---
### 5. debug-mode-test.php - 调试模式测试程序
**特点:**
- ✅ 演示 `--debug-info` 参数的使用
- ✅ 禁用优化,便于调试
- ✅ 生成完整的调试信息
- ✅ 支持 GDB、LLDB、Visual Studio 调试
**编译命令:**
```bash
# 启用调试模式(自动禁用优化 + 生成调试信息)
php ../../cli.php build --mode=bin --debug-info --no-console debug-mode-test.php
# 结合 AddressSanitizer
php ../../cli.php build --mode=bin --debug-info --sanitize=address --no-console debug-mode-test.php
```
**使用方法:**
1. 编译带调试信息的版本
2. 使用调试器加载程序
3. 设置断点、查看变量、单步执行
4. 查看 `debug-mode-test.log` 了解运行流程
---
## 🔧 核心功能
### C++ 函数导出
本示例展示了如何将 C++ 函数导出为 PHP 函数:
1. **函数命名规范**:必须以 `php_` 为前缀
2. **类型要求**:只能使用 PHPX 类型(Int, String, Bool 等)
3. **Stub 声明**:必须在 `.stub.php` 文件中声明函数签名
**示例:**
C++ 实现 (`cpp-src/winapi.cc`):
```cpp
Int php_messagebox(Int hWnd, String text, String caption, Int uType) {
// 实现代码
}
```
PHP Stub 声明 (`cpp-src/winapi.stub.php`):
```php
function messagebox(int $hWnd, string $text, string $caption, int $uType): int {}
```
### 中文支持
#### C++ 层(消息框)
使用 `MultiByteToWideChar` 将 UTF-8 转换为 UTF-16:
```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');
```
---
## 📖 详细文档
- [WINDOWS_GUI_GUIDE.md](./WINDOWS_GUI_GUIDE.md) - Windows GUI 程序完整指南
- [CHINESE_SUPPORT_GUIDE.md](./CHINESE_SUPPORT_GUIDE.md) - 中文支持详细说明
- [CPP_FUNCTION_EXPORT_GUIDE.md](./CPP_FUNCTION_EXPORT_GUIDE.md) - C++ 函数导出规范
---
## 🚀 快速开始
### 编译控制台版本
```bash
# 进入示例目录
cd examples/win32-hello
# 编译
php ../../cli.php build --mode=bin hello-console.php
# 运行
.\hello-console.exe
```
### 编译 GUI 版本
```bash
# 进入示例目录
cd examples/win32-hello
# 编译(使用 --no-console 参数)
php ../../cli.php build --mode=bin --no-console hello-gui.php
# 运行
.\hello-gui.exe
```
---
## 💡 使用场景对比
| 场景 | 推荐模式 | 原因 |
|------|---------|------|
| 命令行工具 | 控制台模式 | 需要文本输出和输入 |
| 后台服务 | 控制台模式 | 需要日志输出 |
| 开发调试 | 控制台模式 | 便于查看调试信息 |
| 桌面应用 | GUI 模式 | 提供更好的用户体验 |
| 游戏 | GUI 模式 | 全屏或窗口化运行 |
| 工具软件 | GUI 模式 | 图形界面更友好 |
---
## ⚙ 编译选项说明
### --no-console 参数
- **作用**:隐藏控制台窗口,创建纯 GUI 应用程序
- **适用平台**:仅 Windows
- **链接选项**:添加 `/SUBSYSTEM:WINDOWS`
- **注意事项**:
- 控制台输出函数(echo、print 等)将无效
- 需要使用消息框或其他 GUI 元素进行输出
- 调试时建议使用控制台模式
### 其他常用选项
```bash
# 优化级别
php cli.php build -O2 app.php
# 指定输出文件名
php cli.php build -o myapp app.php
# 启用调试信息
php cli.php build --debug-info app.php
# 并行编译
php cli.php build -j 8 app.php
```
---
## 🐛 常见问题
### Q: 为什么我的 echo 不显示?
A: 如果使用了 `--no-console` 参数,控制台被隐藏了。请改用消息框:
```php
messagebox(0, "你的消息", "标题", 0);
```
### Q: 如何调试没有控制台的程序?
A:
1. 使用消息框显示变量值
2. 写入日志文件:`file_put_contents('app.log', $msg, FILE_APPEND)`
3. 临时移除 `--no-console` 参数进行调试
4. 使用 [debug-test.php](./debug-test.php) 示例程序
5. 查看详细的 [DEBUG_GUIDE.md](./DEBUG_GUIDE.md)
### Q: 出现 "Debug Assertion Failed" 错误怎么办?
A: 这通常是由于 CRT 库冲突导致的。解决方法:
1. **重新编译**(编译器已自动添加 `/NODEFAULTLIB` 选项)
```bash
php ../../cli.php build --mode=bin --no-console your-app.php
```
2. **清理构建目录**
```bash
Remove-Item -Recurse -Force build/
php ../../cli.php build --mode=bin --no-console your-app.php
```
3. **使用调试测试程序**
```bash
php ../../cli.php build --mode=bin --no-console debug-test.php
.\debug-test.exe
# 查看 debug-test.log 文件
```
4. **查看详细调试指南**
- 参考 [DEBUG_GUIDE.md](./DEBUG_GUIDE.md)
- 使用 Visual Studio 调试器
- 使用 WinDbg
### Q: 中文显示乱码怎么办?
A: 确保:
1. 源文件使用 UTF-8 编码保存
2. C++ 中使用 `MultiByteToWideChar` 转换编码
3. 使用 `MessageBoxW` 而不是 `MessageBoxA`
4. 在 PHP 中设置正确的时区
### Q: 可以同时显示控制台和窗口吗?
A: 技术上可以,但不推荐。通常的做法是:
- 开发时使用控制台模式便于调试
- 发布时使用 GUI 模式提供更好的用户体验
---
## 📝 项目结构
```
win32-hello/
├── hello-console.php # 控制台版本示例
├── hello-gui.php # GUI 版本示例
├── debug-test.php # 调试测试程序(带日志)
├── debug-mode-test.php # 调试模式测试程序(--debug-info)
├── asan-test.php # AddressSanitizer 测试程序
├── main.php # 另一个示例文件
├── window.php # 窗口创建示例
├── cpp-src/
│ ├── winapi.cc # C++ 实现文件
│ └── winapi.stub.php # PHP Stub 声明
├── WINDOWS_GUI_GUIDE.md # GUI 程序指南
├── CHINESE_SUPPORT_GUIDE.md # 中文支持指南
├── CPP_FUNCTION_EXPORT_GUIDE.md # C++ 函数导出指南
├── DEBUG_GUIDE.md # 调试指南(重要!)
├── DEBUG_MODE_GUIDE.md # 调试模式使用指南
├── SANITIZER_GUIDE.md # AddressSanitizer 使用指南
├── MSVC_WARNINGS_SUPPRESSION.md # MSVC 警告屏蔽说明
└── README.md # 本文件
```
---
## 🔗 相关资源
- [PHPX 编译器文档](https://github.com/swoole/phpx)
- [Windows API 文档](https://docs.microsoft.com/en-us/windows/win32/api/)
- [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)