2021SC@SDUSC
今天继续之前的代码分析,对WeaselServer中的代码进一步进行分析
一、代码分析
1.头文件代码分析:<WeaselIPC.h>
上次分析到了<WeaselUI.h><RimeWithWeasel.h><WeaselUtility.h>图形化头文件部分,今天继续分析代码中其它的头文件,首先来看一下WeaselIPC的代码:
#pragma once
#include <WeaselCommon.h>
#include <WeaselUtility.h>
#include <windows.h>
#include <functional>
#include <memory>
#define WEASEL_IPC_WINDOW L"WeaselIPCWindow_1.0"
#define WEASEL_IPC_PIPE_NAME L"WeaselNamedPipe"
#define WEASEL_IPC_METADATA_SIZE 1024
#define WEASEL_IPC_BUFFER_SIZE (4 * 1024)
#define WEASEL_IPC_BUFFER_LENGTH (WEASEL_IPC_BUFFER_SIZE / sizeof(WCHAR))
#define WEASEL_IPC_SHARED_MEMORY_SIZE (sizeof(PipeMessage) + WEASEL_IPC_BUFFER_SIZE)
enum WEASEL_IPC_COMMAND
{
WEASEL_IPC_ECHO = (WM_APP + 1),
WEASEL_IPC_START_SESSION,
WEASEL_IPC_END_SESSION,
WEASEL_IPC_PROCESS_KEY_EVENT,
WEASEL_IPC_SHUTDOWN_SERVER,
WEASEL_IPC_FOCUS_IN,
WEASEL_IPC_FOCUS_OUT,
WEASEL_IPC_UPDATE_INPUT_POS,
WEASEL_IPC_START_MAINTENANCE,
WEASEL_IPC_END_MAINTENANCE,
WEASEL_IPC_COMMIT_COMPOSITION,
WEASEL_IPC_CLEAR_COMPOSITION,
WEASEL_IPC_TRAY_COMMAND,
WEASEL_IPC_LAST_COMMAND
};
namespace weasel
{
struct PipeMessage {
WEASEL_IPC_COMMAND Msg;
UINT wParam;
UINT lParam;
};
struct IPCMetadata
{
enum { WINDOW_CLASS_LENGTH = 64 };
UINT32 server_hwnd;
WCHAR server_window_class[WINDOW_CLASS_LENGTH];
};
struct KeyEvent
{
UINT keycode : 16;
UINT mask : 16;
KeyEvent() : keycode(0), mask(0) {}
KeyEvent(UINT _keycode, UINT _mask) : keycode(_keycode), mask(_mask) {}
KeyEvent(UINT x)
{
*reinterpret_cast<UINT*>(this) = x;
}
operator UINT32 const() const
{
return *reinterpret_cast<UINT32 const*>(this);
}
};
// 處理請求之物件
struct RequestHandler
{
using EatLine = std::function<bool(std::wstring&)>;
RequestHandler() {}
virtual ~RequestHandler() {}
virtual void Initialize() {}
virtual void Finalize() {}
virtual UINT FindSession(UINT session_id) { return 0; }
virtual UINT AddSession(LPWSTR buffer, EatLine eat = 0) { return 0; }
virtual UINT RemoveSession(UINT session_id) { return 0; }
virtual BOOL ProcessKeyEvent(KeyEvent keyEvent, UINT session_id, EatLine eat) { return FALSE; }
virtual void CommitComposition(UINT session_id) {}
virtual void ClearComposition(UINT session_id) {}
virtual void FocusIn(DWORD param, UINT session_id) {}
virtual void FocusOut(DWORD param, UINT session_id) {}
virtual void UpdateInputPosition(RECT const& rc, UINT session_id) {}
virtual void StartMaintenance() {}
virtual void EndMaintenance() {}
virtual void SetOption(UINT session_id, const std::string &opt, bool val) {}
};
// 處理server端回應之物件
typedef std::function<bool (LPWSTR buffer, UINT length)> ResponseHandler;
// 事件處理函數
typedef std::function<bool ()> CommandHandler;
// 啟動服務進程之物件
typedef CommandHandler ServerLauncher;
// IPC實現類聲明
class ClientImpl;
class ServerImpl;
// IPC接口類
class Client
{
public:
Client();
virtual ~Client();
// 连接到服务,必要时启动服务进程
bool Connect(ServerLauncher launcher = 0);
// 断开连接
void Disconnect();
// 终止服务
void ShutdownServer();
// 發起會話
void StartSession();
// 結束會話
void EndSession();
// 進入維護模式
void StartMaintenance();
// 退出維護模式
void EndMaintenance();
// 测试连接
bool Echo();
// 请求服务处理按键消息
bool ProcessKeyEvent(KeyEvent const& keyEvent);
// 上屏正在編輯的文字
bool CommitComposition();
// 清除正在編輯的文字
bool ClearComposition();
// 更新输入位置
void UpdateInputPosition(RECT const& rc);
// 输入窗口获得焦点
void FocusIn();
// 输入窗口失去焦点
void FocusOut();
// 托盤菜單
void TrayCommand(UINT menuId);
// 读取server返回的数据
bool GetResponseData(ResponseHandler handler);
private:
ClientImpl* m_pImpl;
};
class Server
{
public:
Server();
virtual ~Server();
// 初始化服务
int Start();
// 结束服务
int Stop();
// 消息循环
int Run();
void SetRequestHandler(RequestHandler* pHandler);
void AddMenuHandler(UINT uID, CommandHandler handler);
HWND GetHWnd();
private:
ServerImpl* m_pImpl;
};
inline std::wstring GetPipeName()
{
std::wstring pipe_name;
pipe_name += L"\\\\.\\pipe\\";
pipe_name += getUsername();
pipe_name += L"\\";
pipe_name += WEASEL_IPC_PIPE_NAME;
return pipe_name;
}
}
IPC(Inter-Process Communication,进程间通信)。进程间通信是指两个进程的数据之间产生交互,<WeaselIPC.h>中的代码主要涉及到对进程间通信所涉及到的常量以及相关的一些具体给出了定义,在头文件中的相关操作都是以抽象方法的方式给出的,具体的解决代码是在调用这些方法时给出的,接下来对<WeaselIPC.h>中的各个部分代码模块进行分析:
1)开头常量定义部分
#define WEASEL_IPC_WINDOW L"WeaselIPCWindow_1.0"
#define WEASEL_IPC_PIPE_NAME L"WeaselNamedPipe"
#define WEASEL_IPC_METADATA_SIZE 1024
#define WEASEL_IPC_BUFFER_SIZE (4 * 1024)
#define WEASEL_IPC_BUFFER_LENGTH (WEASEL_IPC_BUFFER_SIZE / sizeof(WCHAR))
#define WEASEL_IPC_SHARED_MEMORY_SIZE (sizeof(PipeMessage) + WEASEL_IPC_BUFFER_SIZE)
第一句定义了一个名叫WEASEL_IPC_WINDOW的变量,*具体含义暂时不明确,应该时涉及到对于进程的定位,第二句定位了进程间通信所涉及的管道pipe名,说明进程间的通信涉及到了管道技术,并且都涉及到了同一个名为WeaselNamedPipe的管道,接下来的四个常量定义了临时存储空间buffer相关的存储属性,第一个WEASEL_IPC_METADATA_SIZE规定了buffer中单位数据的长度:1024字节也就是1kb,第二个常量WEASEL_IPC_BUFFER_SIZE规定了buffer的总长度,一共四个单位长度,也就是一共4kb的存储空间,第三个常量WEASEL_IPC_BUFFER_LENGTH规定了buffer中可以存储的WCHAR类型数据的个数,也就是buffer的存储长度,第四个常量WEASEL_IPC_SHARED_MEMORY_SIZE通过计算得出了系统需要分配给进程间进行相互通信所需要的存储空间的大小:pipe管道中所存储的信息的长度加上进程间共享空间buffer的长度。
2)namespace weasel
接下来我们分析namespace weasel中所涉及的内容:
namespace weasel
{
struct PipeMessage {
WEASEL_IPC_COMMAND Msg;
UINT wParam;
UINT lParam;
};
struct IPCMetadata
{
enum { WINDOW_CLASS_LENGTH = 64 };
UINT32 server_hwnd;
WCHAR server_window_class[WINDOW_CLASS_LENGTH];
};
struct KeyEvent
{
UINT keycode : 16;
UINT mask : 16;
KeyEvent() : keycode(0), mask(0) {}
KeyEvent(UINT _keycode, UINT _mask) : keycode(_keycode), mask(_mask) {}
KeyEvent(UINT x)
{
*reinterpret_cast<UINT*>(this) = x;
}
operator UINT32 const() const
{
return *reinterpret_cast<UINT32 const*>(this);
}
};
// 處理請求之物件
struct RequestHandler
{
using EatLine = std::function<bool(std::wstring&)>;
RequestHandler() {}
virtual ~RequestHandler() {}
virtual void Initialize() {}
virtual void Finalize() {}
virtual UINT FindSession(UINT session_id) { return 0; }
virtual UINT AddSession(LPWSTR buffer, EatLine eat = 0) { return 0; }
virtual UINT RemoveSession(UINT session_id) { return 0; }
virtual BOOL ProcessKeyEvent(KeyEvent keyEvent, UINT session_id, EatLine eat) { return FALSE; }
virtual void CommitComposition(UINT session_id) {}
virtual void ClearComposition(UINT session_id) {}
virtual void FocusIn(DWORD param, UINT session_id) {}
virtual void FocusOut(DWORD param, UINT session_id) {}
virtual void UpdateInputPosition(RECT const& rc, UINT session_id) {}
virtual void StartMaintenance() {}
virtual void EndMaintenance() {}
virtual void SetOption(UINT session_id, const std::string &opt, bool val) {}
};
// 處理server端回應之物件
typedef std::function<bool (LPWSTR buffer, UINT length)> ResponseHandler;
// 事件處理函數
typedef std::function<bool ()> CommandHandler;
// 啟動服務進程之物件
typedef CommandHandler ServerLauncher;
// IPC實現類聲明
class ClientImpl;
class ServerImpl;
// IPC接口類
class Client
{
public:
Client();
virtual ~Client();
// 连接到服务,必要时启动服务进程
bool Connect(ServerLauncher launcher = 0);
// 断开连接
void Disconnect();
// 终止服务
void ShutdownServer();
// 發起會話
void StartSession();
// 結束會話
void EndSession();
// 進入維護模式
void StartMaintenance();
// 退出維護模式
void EndMaintenance();
// 测试连接
bool Echo();
// 请求服务处理按键消息
bool ProcessKeyEvent(KeyEvent const& keyEvent);
// 上屏正在編輯的文字
bool CommitComposition();
// 清除正在編輯的文字
bool ClearComposition();
// 更新输入位置
void UpdateInputPosition(RECT const& rc);
// 输入窗口获得焦点
void FocusIn();
// 输入窗口失去焦点
void FocusOut();
// 托盤菜單
void TrayCommand(UINT menuId);
// 读取server返回的数据
bool GetResponseData(ResponseHandler handler);
private:
ClientImpl* m_pImpl;
};
class Server
{
public:
Server();
virtual ~Server();
// 初始化服务
int Start();
// 结束服务
int Stop();
// 消息循环
int Run();
void SetRequestHandler(RequestHandler* pHandler);
void AddMenuHandler(UINT uID, CommandHandler handler);
HWND GetHWnd();
private:
ServerImpl* m_pImpl;
};
inline std::wstring GetPipeName()
{
std::wstring pipe_name;
pipe_name += L"\\\\.\\pipe\\";
pipe_name += getUsername();
pipe_name += L"\\";
pipe_name += WEASEL_IPC_PIPE_NAME;
return pipe_name;
}
}
为了确保代码的可用性,这里用一个namespace将此代码块进行了封装,当namespace weasel中的代码与其他部分代码重名的时候就可以利用不同的namespace进行区分。
struct PipeMessage {
WEASEL_IPC_COMMAND Msg;
UINT wParam;
UINT lParam;
};
结构体PipeMessage中定义了pipemessage的具体内容,由一个WEASEL_IPC_COMMAND命令Msg和两个无符号数wParam和lParam组成,IPC命令主要是向进程发出具体的操作命令,两个无符号数的作用将在接下来的部分进行讨论。
struct IPCMetadata
{
enum { WINDOW_CLASS_LENGTH = 64 };
UINT32 server_hwnd;
WCHAR server_window_class[WINDOW_CLASS_LENGTH];
};
结构体IPCMetadata规定了IPC元数据的相关属性,enum枚举变量规定元数据的长度为64个字节,第二个32位的无符号数server_hwnd用于存储窗口或者控件的句柄,以此来实现对不同进程以及不同控件之间的区分,第三个是一个WCHAR类型的变量sever_window_class数组,wchar_t是C/C++的字符类型,是一种扩展的存储方式。wchar_t类型主要用在国际化程序的实现中,但它不等同于unicode编码。unicode编码的字符一般以wchar_t类型存储,wchar_t数据类型一般为16位或32位,但不同的C或C++库有不同的规定,如GNU Libc规定wchar_t为32位,总之,wchar_t所能表示的字符数远超char型,*这个数组具体作用我们将在后续篇章中进行讨论。
struct KeyEvent
{
UINT keycode : 16;
UINT mask : 16;
KeyEvent() : keycode(0), mask(0) {}
KeyEvent(UINT _keycode, UINT _mask) : keycode(_keycode), mask(_mask) {}
KeyEvent(UINT x)
{
*reinterpret_cast<UINT*>(this) = x;
}
operator UINT32 const() const
{
return *reinterpret_cast<UINT32 const*>(this);
}
};
* KeyEvent结构体定义了主事件的相关内容,其中keycode的长度为16个字节,mask的长度为16个字节,主事件的具体作用目前尚不明确。
struct RequestHandler
{
using EatLine = std::function<bool(std::wstring&)>;
RequestHandler() {}
virtual ~RequestHandler() {}
virtual void Initialize() {}
virtual void Finalize() {}
virtual UINT FindSession(UINT session_id) { return 0; }
virtual UINT AddSession(LPWSTR buffer, EatLine eat = 0) { return 0; }
virtual UINT RemoveSession(UINT session_id) { return 0; }
virtual BOOL ProcessKeyEvent(KeyEvent keyEvent, UINT session_id, EatLine eat) { return FALSE; }
virtual void CommitComposition(UINT session_id) {}
virtual void ClearComposition(UINT session_id) {}
virtual void FocusIn(DWORD param, UINT session_id) {}
virtual void FocusOut(DWORD param, UINT session_id) {}
virtual void UpdateInputPosition(RECT const& rc, UINT session_id) {}
virtual void StartMaintenance() {}
virtual void EndMaintenance() {}
virtual void SetOption(UINT session_id, const std::string &opt, bool val) {}
};
结构体RequestHandler中定义了很多对于请求处理的相关虚拟方法,并给出了方法中所需要的相关参数的具体类型。