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.
 
 

5.9 KiB

Windows GUI 程序指南

概述

本示例展示了如何使用 PHPX 编译器创建纯图形界面的 Windows 程序,不显示控制台窗口。

关键特性

1. 隐藏控制台窗口

通过添加 --no-console 编译参数,程序将以 Windows 子系统模式运行,不会显示黑色的控制台终端窗口。

使用方法:

php cli.php build --mode=bin --no-console your-app.php

实现位置:

  • 选项定义:src/Php/Constants.php
  • 参数读取:src/Php/Translator.php
  • 链接配置:src/Php/CompilerBase.php
// 对于 bin 模式且指定了 --no-console,使用 Windows 子系统(不显示控制台窗口)
if ($this->buildMode === 'bin' && $this->noConsole) {
    $cmd .= ' /SUBSYSTEM:WINDOWS';
}

2. 中文支持

C++ 层(消息框)

在 C++ 中使用 MultiByteToWideChar 将 UTF-8 转换为 UTF-16,然后调用 MessageBoxW

// 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 层(时区设置)

// Set timezone to China (UTC+8)
date_default_timezone_set('Asia/Shanghai');

3. 输出方式

由于没有控制台窗口,所有输出必须通过 GUI 元素显示:

  • 消息框:使用 messagebox()MessageBox() 函数
  • 自定义窗口:需要实现完整的窗口类和消息循环
  • 日志文件:可以写入文件进行调试

编译和运行

带控制台窗口(默认)

# 进入示例目录
cd examples/win32-hello

# 编译为带控制台的程序(默认)
php ../../cli.php build --mode=bin hello-win.php

# 运行程序(显示控制台和消息框)
.\hello-win.exe

不带控制台窗口(GUI 模式)

# 使用 --no-console 参数编译纯 GUI 程序
php ../../cli.php build --mode=bin --no-console hello-win.php

# 运行程序(只显示消息框,无控制台)
.\hello-win.exe

注意事项

重要限制

  1. 没有标准输入输出

    • echoprintprintf 等控制台输出函数无效
    • stdinstdoutstderr 不可用
    • 所有输出必须通过 GUI 元素
  2. 调试困难

    • 无法在控制台查看调试信息
    • 建议使用:
      • 消息框显示调试信息
      • 写入日志文件
      • 使用 Visual Studio 调试器附加进程
  3. 入口点要求

    • 使用 /SUBSYSTEM:WINDOWS 后,默认入口点是 WinMain 而不是 main
    • PHPX 编译器会自动处理这个转换

最佳实践

  1. 使用消息框进行用户交互

    messagebox(0, "操作成功!", "提示", 0);
    
  2. 错误处理

    try {
        // 你的代码
    } catch (\Exception $e) {
        messagebox(0, "错误: " . $e->getMessage(), "错误", 16); // MB_ICONERROR
    }
    
  3. 日志记录

    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 应用程序
用户体验 黑色终端窗口 纯图形界面

切换模式

开发时(带控制台,便于调试)

# 默认编译,显示控制台
php cli.php build --mode=bin app.php

发布时(不带控制台,纯 GUI)

# 使用 --no-console 参数
php cli.php build --mode=bin --no-console app.php

在 project.yml 中配置

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

function main()
{
    date_default_timezone_set('Asia/Shanghai');
    
    // 欢迎消息
    messagebox(0, 
        "欢迎使用!\n\n" .
        "当前时间: " . date('Y-m-d H:i:s'), 
        "Hello", 
        0);
}

带错误处理的程序

<?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
    }
}

相关资源