Wine debug笔记

wine基础知识可参见:
https://www.cnblogs.com/chendeqiang/p/14309515.html
https://wiki.winehq.org/Main_Page

替换OpenFileDialog对话框

这是我的第一个课题,尽管失败了,仍然值得纪念。

目的:使用系统调用对话框代替Wine原生的windows对话框。
工具:vscode,shell,ubuntu20.04,windows
前期准备:windows 窗口调用学习,了解创建窗口,消息传递等基本知识。
wine原生对话框
对标对话框
历时:7天。

首先想到的是替换explore风格,来整体替换对话框风格,但是没有找到可替换或更改的地方。
在追踪过程中,调研到了打开文件对话框函数,通过阅读msdn文档,对打开/保存文件对话框函数和概念有了一些了解。

由于这是第一次使用Windows API,因此大多数时间都花在了查阅和使用windows api上。

接下来想到自己做一个gtk的二进制,然后通过调用gtk二进制来取代windows api的调用。

首先是学习gtk窗口基本知识

然后制作了一个对话框窗口demo

接下来是替换wine源码中打开文件对话框的调用。
定位函数:DialogOpenFile:

static void DialogOpenFile(void)
{
    //文件样式控制
    OPENFILENAMEW ofn;

    WCHAR wszFile[MAX_PATH] = {'\0'};
    static const WCHAR wszDefExt[] = {'r','t','f','\0'};

    ZeroMemory(&ofn, sizeof(ofn));

    ofn.lStructSize = sizeof(ofn);
    ofn.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_ENABLESIZING;
    ofn.hwndOwner = hMainWnd;
    ofn.lpstrFilter = wszFilter;
    ofn.lpstrFile = wszFile;
    ofn.nMaxFile = MAX_PATH;
    ofn.lpstrDefExt = wszDefExt;
    ofn.nFilterIndex = fileformat_number(fileFormat)+1;

    if(GetOpenFileNameW(&ofn))
    {
        if(prompt_save_changes())
            //很明显此处传入 ofn.lpstrFile 作为文件名,然后执行了打开文件对话框,因此我的想法是该写GetOpenFileNameW函数
            DoOpenFile(ofn.lpstrFile);
    }
}

查看GetOpenFileNameW函数:

BOOL WINAPI GetOpenFileNameW(OPENFILENAMEW *ofn)
{
    TRACE("flags 0x%08x\n", ofn->Flags);

    if (!valid_struct_size( ofn->lStructSize ))
    {
        COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
        return FALSE;
    }

    /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
    if (ofn->Flags & OFN_FILEMUSTEXIST)
        ofn->Flags |= OFN_PATHMUSTEXIST;

    if (is_win16_looks(ofn->Flags))
        return GetFileName31W(ofn, OPEN_DIALOG);
    else
    {
        FileOpenDlgInfos info;

        init_filedlg_infoW(ofn, &info);
        return GetFileDialog95(&info, OPEN_DIALOG);
    }
}

我的想法很简单,先测试一个demo,把GetOpenFileNameW中的代码都屏蔽,然后使用system调用:

BOOL WINAPI GetOpenFileNameW(OPENFILENAMEW *ofn)
{
//cdq
#if 1
    system("~/myOpenFileDialog.out");
#else
    TRACE("flags 0x%08x\n", ofn->Flags);

    if (!valid_struct_size( ofn->lStructSize ))
    {
        COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
        return FALSE;
    }

    /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
    if (ofn->Flags & OFN_FILEMUSTEXIST)
        ofn->Flags |= OFN_PATHMUSTEXIST;

    if (is_win16_looks(ofn->Flags))
        return GetFileName31W(ofn, OPEN_DIALOG);
    else
    {
        FileOpenDlgInfos info;

        init_filedlg_infoW(ofn, &info);
        return GetFileDialog95(&info, OPEN_DIALOG);
    }

}
#endif

接下来就是灾难了,
这个文件名我不会传回来,

大体上我想了两种方案,一种是将gtk编入wine,另一种是进程间通信。

如果将gtk编入wine,就需要在wine工程中引入gtk 代码,整个makefile也需要重新改写,我尝试了一段时间后,觉得代价太大了,会破坏wine工程,就放弃了。

第二种方案是我制作一个可执行程序,应用进程间通信的方式传入文件名。

进程间通信我先后用了管道,公共文件读写,共享内存等方式,
最后总是父进程总是不等待子进程结束就继续执行了,即没等文件名返回父进程就已经执行打开文件的操作了。

经过一系列的调研,发现wine中混用了windows和linux的进程和线程,最后通过wineserve统一管理进程间通信问题,
但是没有找到wineserve的使用方法,而且进程间通信的问题入门有点难了,就放弃了这个课题。

Foxmail无法发送邮件

目的:解决Foxmail无法发送邮件的问题。
现象:
1.在收件人地址栏写入收件人后,如果加上分号,无法显示收件人
2.点击发送后邮件发送失败
3.在草稿箱可以看到邮件人地址除了正常收件人地址外还多了一个“?”
历时:10天
工具:QtCreater,KylinV10Pro

首先是复现bug:
这个bug是在crossover上出现的,
但是我用wine运行foxmail时和crossover的表现不一样:
crossover表现

那么wine为什么会和crossover表现的不一样,是因为crossover单独维护了一个wine版本吗?

经过一系列调查,我发现问题可能在于wine缺少html渲染,导致所有html都无法显示,

我新建了一个wine容器,发现果然wine内置了html引擎,

接下来我拷贝了这个crossover新建的容器,并命名为~/.wine

然后再启动Foxmail,

果然发现wine和crossover表现一致了,因此这个bug也可以复现了。

然后是问题识别:
一开始结论是收件人地址栏不显示收件人导致数据发不出去。

后续调查发现,收件人不显示不影响邮件发送,
那么这个bug就不是一个bug而是两个bug:
1.收件人不显示
2.邮件发不出去

先解决邮件发不出去的问题。
从发送失败后的草稿箱来看,收件人地址多了一个“?”

为了复现这个现象,我模拟了一个错误地址发送,发现触发了同样的错误提示,但是一些无效字符会被Foxmail处理掉。

所以现在肯定,就是这个多出来的“?”导致邮件发不出去,

那么多出来的是什么呢?

我的第一直觉多出来的是‘\r’转义字符;因为windows的换行符是‘\r\n’,Linux的换行符是'\n',所以肯定是'\r'在linux下无法被识别,且被当成了有效字符,所以变成了“?”,导致邮件发不出去。

posted @ 2021-03-11 08:42  多弗朗强哥  阅读(408)  评论(0编辑  收藏  举报