国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發 > 綜合 > 正文

基于 Linux 和 MiniGUI 的嵌入式系統軟件開發指南(六)

2024-07-21 02:38:20
字體:
來源:轉載
供稿:網友

  作者:魏永明
  
  MiniGUI 提供的非 GUI/GDI 接口
  
  本文講述了 MiniGUI 為應用程序提供的非 GUI/GDI 接口,這些接口能夠幫助應用程序更好地和操作系統交互,擴展應用程序功能,并提高應用程序的可移植性。內容主要涉及到如下幾個方面:MiniGUI-Lite 和 select 系統調用;基于 UNIX Domain Socket 的進程間通訊;編寫可移植性代碼等。
  1 引言
  一般而言,GUI 系統的應用程序編程接口主要集中于窗口、消息隊列、圖形設備等相關方面。但因為 GUI 系統在處理系統事件時通常會提供自己的機制,而這些機制往往會和操作系統本身提供的機制不相兼容。比如,MiniGUI 提供了消息循環機制,而應用程序的結構一般是消息驅動的;也就是說,應用程序通過被動接收消息來工作。但很多情況下,應用程序需要主動監視某個系統事件,比如在 UNIX 操作系統中,可以通過 select 系統調用監聽某個文件描述符上是否有可讀數據。這樣,如何將 MiniGUI 的消息隊列機制和現有操作系統的其他機制融合在一起,就成了一個較為困難的問題。本文將講述幾種解決這一問題的方法。
  
  我們知道,MiniGUI-Lite 采用 UNIX Domain Socket 實現客戶程序和服務器程序之間的交互。應用程序也可以利用這一機制,完成自己的通訊任務――客戶向服務器提交請求,而服務器完成對客戶的請求處理并應答。一方面,在 MiniGUI-Lite 的服務器程序中,你可以擴展這一機制,注冊自己的請求處理函數,完成定制的請求/響應通訊任務。另一方面,MiniGUI-Lite 當中也提供了若干用來創建和操作 UNIX Domain Socket 的函數,任何 MiniGUI-Lite 的應用程序都可以建立 UNIX Domain Socket,并完成和其他 MiniGUI-Lite 應用程序之間的數據交換。本文將舉例講述如何利用 MiniGUI-Lite 提供的函數完成此類通訊任務。
  
  嵌入式 linux 系統現在能夠在許多不同架構的硬件平臺上運行,MiniGUI 也能夠在這些硬件平臺上運行。但由于許多硬件平臺具有和其他硬件平臺不同的特性,比如說,常見的 CPU 是 Little Endian 的,而某些 CPU 則是 Big Endian 的。這要求我們在編寫代碼,尤其是文件 I/O 相關代碼時,必須編寫可移植代碼,以便適合具有不同架構的平臺。本文將描述 MiniGUI 為應用程序提供的可移植性函數及其用法。
  
  除了與上述內容相關的函數之外,MiniGUI 還提供了其他一些函數,本文最后部分將描述這些函數的用途和用法,包括配置文件讀寫以及定點數運算。
  
  2 MiniGUI-Lite和 select 系統調用
  我們知道,在 MiniGUI-Lite 之上運行的應用程序只有一個消息隊列。應用程序在初始化之后,會建立一個消息循環,然后不停地從這個消息隊列當中獲得消息并處理,直到接收到 MSG_QUIT 消息為止。應用程序的窗口過程在處理消息時,要在處理完消息之后立即返回,以便有機會獲得其他的消息并處理。現在,假如應用程序在處理某個消息時監聽某個文件描述符而調用 select 系統調用,就有可能會出現問題――因為 select 系統調用可能會長時間阻塞,而由 MiniGUI-Lite 服務器發送給客戶的事件得不到及時處理。這樣,消息驅動的方式和 select 系統調用就難于很好地融合。在 MiniGUI-Threads 中,因為每個線程都有自己相應的消息隊列,而系統消息隊列是由單獨運行的 desktop 線程治理的,所以任何一個應用程序建立的線程都可以長時間阻塞,從而可以調用類似 select 的系統調用。但在 MiniGUI-Lite 當中,假如要監聽某個應用程序自己的文件描述符事件,必須進行恰當的處理,以避免長時間阻塞。
  
  在 MiniGUI-Lite 當中,有幾種解決這一問題的辦法:
  
  在調用 select 系統調用時,傳遞超時值,保證 select 系統調用不會長時間阻塞。
  設置定時器,定時器到期時,利用 select 系統調用查看被監聽的文件描述符。假如沒有相應的事件發生,則立即返回,否則進行讀寫操作。
  利用 MiniGUI-Lite 提供的 RegisterListenFD 函數在系統中注冊監聽文件描述符,并在被監聽的文件描述符上發生指定的事件時,向某個窗口發送 MSG_FDEVENT 消息。
  
  由于前兩種解決方法比較簡單,這里我們重點講述的第三種解決辦法。MiniGUI-Lite 為應用程序提供了如下兩個函數及一個宏:
  #define MAX_NR_LISTEN_FD 5
  
  /* Return TRUE if all OK, and FALSE on error. */
  BOOL GUIAPI RegisterListenFD (int fd, int type, HWND hwnd, void* context);
  
  /* Return TRUE if all OK, and FALSE on error. */
  BOOL GUIAPI UnregisterListenFD (int fd);
  
  MAX_NR_LISTEN_FD 宏定義了系統能夠監聽的最多文件描述符數,默認定義為 5。

  RegisterListenFD 函數在系統當中注冊一個需要監聽的文件描述符,并指定監聽的事件類型(type 參數,可取 POLLIN、POLLOUT 或者 POLLERR),接收 MSG_FDEVENT 消息的窗口句柄以及一個上下文信息。
  UnregisterListenFD 函數注銷一個被注冊的監聽文件描述符。
  
  在應用程序使用RegisterListenFD 函數注冊了被監聽的文件描述符之后,當指定的事件發生在該文件描述符上時,系統會將 MSG_FDEVENT 消息發送到指定的窗口,應用程序可在窗口過程中接收該消息并處理。MiniGUI 中的 libvcongui 就利用了上述函數監聽來自主控偽終端上的可讀事件,如下面的程序段所示(vcongui/vcongui.c):
   ...
  
   /* 注冊主控偽終端偽監聽文件描述符 */
   RegisterListenFD (pConInfo->masterPty, POLLIN, hMainWnd, 0);
  
   /* 進入消息循環 */
   while (!pConInfo->terminate && GetMessage (&Msg, hMainWnd)) {
   DispatchMessage (&Msg);
   }
   /* 注銷監聽文件描述符 */
   UnregisterListenFD (pConInfo->masterPty);
  
   ...
  
  /* 虛擬控制臺的窗口過程 */
  static int VCOnGUIMainWinPRoc (HWND hWnd, int message, WPARAM wParam, LPARAM lParam)
  {
   PCONINFO pConInfo;
  
   pConInfo = (PCONINFO)GetWindowAdditionalData (hWnd);
   switch (message) {
  
   ...
  
   /* 接收到 MSG_FDEVENT 消息,則處理主控偽終端上的輸入數據 */
   case MSG_FDEVENT:
   ReadMasterPty (pConInfo);
   break;
  
   ...
   }
  
   /* 調用默認窗口過程 */
   if (pConInfo->DefWinProc)
   return (*pConInfo->DefWinProc)(hWnd, message, wParam, lParam);
   else
   return DefaultMainWinProc (hWnd, message, wParam, lParam);
  }
  
  在 3.2 節當中,我們還可以看到RegisterListenFD 函數的使用。顯然,通過這種簡單的注冊監聽文件描述符的接口,MiniGUI-Lite 程序能夠方便地利用底層的消息機制完成對異步事件的處理。
  
  3 MiniGUI-Lite 與進程間通訊
  
  3.1 簡單請求/應答處理
  我們知道,MiniGUI-Lite 利用了 UNIX Domain Socket 實現服務器和客戶程序之間的通訊。為了實現客戶和服務器之間的簡單方便的通訊,MiniGUI-Lite 中定義了一種簡單的請求/響應結構。客戶程序通過指定的結構將請求發送到服務器,服務器處理請求并應答。在客戶端,一個請求定義如下(include/gdi.h):
  typedef strUCt tagREQUEST {
   int id;
   const void* data;
   size_t len_data;
  } REQUEST;
  typedef REQUEST* PREQUEST;
  
  其中,id 是用來標識請求類型的整型數,data 是發送給該請求的關聯數據,len_data 則是數據的長度。客戶在初始化 REQUEST 結構之后,就可以調用 cli_request 向服務器發送請求,并等待服務器的應答。該函數的原型如下。
  /* send a request to server and wait reply */
  int cli_request (PREQUEST request, void* result, int len_rslt);
  
  
  
  
  服務器程序(即 mginit)會在自己的消息循環當中獲得來自客戶的請求,并進行處理,最終會將處理結果發送給客戶。
  
  在上述這種簡單的客戶/服務器通訊中,客戶和服務器必須就每個請求類型達成一致,也就是說,客戶和服務器必須了解每種類型請求的數據含義并進行恰當的處理。
  
  MiniGUI-Lite 利用上述這種簡單的通訊方法,實現了若干系統級的通訊任務:
  
  鼠標光標的治理。鼠標光標是一個全局資源,當客戶需要創建或者銷毀鼠標光標,改變鼠標光標的外形、位置,顯示或者隱藏鼠標時,就發送請求到服務器,服務器程序完成相應任務并將結果發送給客戶。
  層及活動客戶治理。當客戶查詢層的信息,新建層,加入某個已有層,或者設置層中的活動客戶時,通過該接口發送請求到服務器。
  其他一些系統級的任務。比如在新的 GDI 接口中,服務器程序統一治理顯示卡中可能用來建立內存 DC 的顯示內存,當客戶要申請建立在顯示內存中的內存 DC 時,就會發送請求到服務器。
  
  為了讓應用程序也能夠通過這種簡單的方式實現客戶和服務器之間的通訊,服務器程序可以注冊一些定制的請求處理函數,然后客戶就可以向服務器發送這些請求。
為此,MiniGUI-Lite 提供了如下接口:
  #define MAX_SYS_REQID 0x0010
  #define MAX_REQID 0x0018
  
  /*
   * Register user defined request handlers for server
   * Note that user defined request id should larger

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 都昌县| 响水县| 伊金霍洛旗| 石门县| 都兰县| 遵义县| 铁岭市| 库伦旗| 长宁县| 陇西县| 赣榆县| 青铜峡市| 普陀区| 桑日县| 屯门区| 伽师县| 察隅县| 伊川县| 庐江县| 鄯善县| 阿克苏市| 惠安县| 陵水| 桦甸市| 开阳县| 太仓市| 松溪县| 安达市| 宁波市| 郴州市| 吴旗县| 泰和县| 汉川市| 苏尼特右旗| 北安市| 景谷| 原平市| 团风县| 工布江达县| 和龙市| 大理市|