wine基础知识可参见:
https://www.cnblogs.com/chendeqiang/p/14309515.html
https://wiki.winehq.org/Main_Page
替换OpenFileDialog对话框
这是我的第一个课题,尽管失败了,仍然值得纪念。
目的:使用系统调用对话框代替Wine原生的windows对话框。
工具:vscode,shell,ubuntu20.04,windows
前期准备:windows 窗口调用学习,了解创建窗口,消息传递等基本知识。
历时: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] = {' '};
static const WCHAR wszDefExt[] = {'r','t','f',' '};
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
", 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
", 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的表现不一样:
那么wine为什么会和crossover表现的不一样,是因为crossover单独维护了一个wine版本吗?
经过一系列调查,我发现问题可能在于wine缺少html渲染,导致所有html都无法显示,
我新建了一个wine容器,发现果然wine内置了html引擎,
接下来我拷贝了这个crossover新建的容器,并命名为~/.wine
然后再启动Foxmail,
果然发现wine和crossover表现一致了,因此这个bug也可以复现了。
然后是问题识别:
一开始结论是收件人地址栏不显示收件人导致数据发不出去。
后续调查发现,收件人不显示不影响邮件发送,
那么这个bug就不是一个bug而是两个bug:
1.收件人不显示
2.邮件发不出去
先解决邮件发不出去的问题。
从发送失败后的草稿箱来看,收件人地址多了一个“?”
为了复现这个现象,我模拟了一个错误地址发送,发现触发了同样的错误提示,但是一些无效字符会被Foxmail处理掉。
所以现在肯定,就是这个多出来的“?”导致邮件发不出去,
那么多出来的是什么呢?
我的第一直觉多出来的是‘ ’转义字符;因为windows的换行符是‘ ’,Linux的换行符是' ',所以肯定是' '在linux下无法被识别,且被当成了有效字符,所以变成了“?”,导致邮件发不出去。