程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> SideShow Gadget本地存儲實現

SideShow Gadget本地存儲實現

編輯:關於.NET

1、說明

標准的Sideshow設備連接PC後,由PC上Sideshow管理中心負責向Sideshow設備添加Gadget應用,該 Gadget實例被Sideshow設備緩存到內存中。當Sideshow設備未連接PC,掉電重啟後,所有原先添加的 Gadget信息將全部丟失。

本功能的目的就是,Sideshow設備在上述情況下重啟,可以自動恢復原先的Gadget應用。

2、Sideshow功能模塊關系圖

SideShow設備啟動後,主界面優先啟動,顯示一些本地Gadget和系統基本信息(日期時間等)。於此 同時Message組件也開始工作,全權接管和PC Sideshow相關的通信功能,新的Gadget也就是通過該通道添 加到Sideshow設備中來,新的畫面、信息、狀態也源源不斷由PC向SideShow設備而來,此時SideShow設備 也會根據Gadget的操作情況,主動向PC Sideshow管理中心回傳gadget的狀態信息(包括是否獲得焦點、 按鍵信息、菜單選擇信息等等)。

當Gadget相關信息由PC過來時,會先存儲到Cache中去,並不直接顯示相關畫面,UI引擎根據需要,會 隨時從Cache中獲取相關界面元素。

3、Gadget本地存儲實現

3.1、實現思路

雖然所有的UI信息都緩存到Cache中,但是由於顯示Gadget是一個動態過程,是顯示引擎根據需要,動 態從Cache中構建Gadget。而該需要就是Message組件通知並促成的。如果僅僅把Cache的內存持久化,而 不啟動消息循環引擎,Gadget是無法加載並應用的。

一切的根源來至於Message組件中的各種不同的消息,所以最直接的思路就是截獲並持久化相關消息, 並在設備啟動時(要先判斷是否聯機,如果已聯機,則不執行任何代碼),讀取並投送相關消息,模擬 Sideshow設備聯機時的相關信息交互,從而實現了Gadget非聯機狀態情況下的動態加載,由於是通過模擬 消息方式實現了Gadget的加載,所以此時Gadget的功能和聯機時無異(注意:由於沒有聯機,所以Gadget 顯示的信息和內容是非即時的)。

3.2、具體實現

3.2.1 消息結構簡介

PC和Sideshow設備相關的消息共74種,消息結構分兩部分,一是消息頭(包含消息指令),二是 Payload(負荷數據),我們要緩存的數據也主要是這兩部分。

詳情可參見《SideShow通信協議》相關文檔。

3.2.2 需要持久化的消息指令

序號 名稱 值 說明 1 AddApp 0x010D 添加gadget 2 DeleteApp 0x010E 刪除指定gadget 3 DeleteAllApps 0x010F 刪除全部gadget 4 AddContentItem 0x0114 添加指定gadget內容項 5 DeleteContentItem 0x0115 刪除指定gadget內容項 6 DeleteAllContentItems 0x0116 刪除指定gadget所有內容項

注:考慮到性能,第5項和第6項消息沒有做相關的處理。

3.2.3 本地存儲格式

首先創建Gadget目錄("ROOT"CADGET_CACHE)

每一個Gadget應用對應一個由其GUID為命名的目錄,目錄中存放兩類信息,一是:index.App,該文件 存放了Gadget的名字和圖標相關信息;二是Gadget內容信息,命令格式 {內容ID}.Content。

3.2.4 Gadget持久化類代碼

 public class GadgetCache

    {

        public static  bool OnlineFlag = false;

        public static bool RunFlag = false;

         public static int CheckCachedDirectory();

        public static string[] EnumApps();

        public static string[] EnumContentItems(string AppId);

        public static int LoadApp(string AppId, out byte[] bytData);

        public static int SaveApp(string AppId, byte[] bytData);

        public static int DeleteApp(string AppId);

         public static int DeleteAllApps();

       public static int LoadContentItem(string AppId, string ContentId, out byte[] bytData);

         public static int SaveContentItem(string AppId, string ContentId, byte[] bytData);

         public static int DeleteContentItem(string AppId, string ContentId);

         public static int DeleteAllContentItems(string AppId);

     }

詳細實現代碼 略

代碼所在的文件:PcMessageHandler.cs

3.2.5 Gadget持久化執行代碼

case PacketType.AddApp:

    {

        ClientInfo info = new ClientInfo();

        Guid appId      = command.ReadGuid();

         Guid endptId    = command.ReadGuid();

        info.Name        = command.ReadString();

        info.Policy     = (CachePolicy) command.ReadInt();

        info.OnLineOnly = command.ReadUint() != 0;

        info.Icon48Data = command.ReadByteArray();

        info.Icon32Data = command.ReadByteArray();

        info.Icon16Data = command.ReadByteArray();

       shell.ConnectClient(appId, endptId, info);

       if (!GadgetCache.RunFlag) GadgetCache.SaveApp(appId.ToString(), msg.Payload);

        break;

    }

case PacketType.AddContentItem:

    {

        Guid appId      = command.ReadGuid();

        Guid endptId    = command.ReadGuid();

         uint contentId = command.ReadUint();

        byte[] itemData = command.ReadByteArray();

        cacheMgr.AddItem(appId, endptId, contentId, itemData);

        if (!GadgetCache.RunFlag) GadgetCache.SaveContentItem (appId.ToString(), contentId.ToString(), msg.Payload);

        break;

    }

case PacketType.DeleteContentItem:

case PacketType.DeleteAllContentItems:

(其它代碼 略)

代碼所在的文件:PcMessageHandler.cs 中的ProcessMessage函數

3.2.6 Gadget本地數據讀取及恢復

1、啟動

new Thread(new ThreadStart(Load_Gadget)).Start();

代碼所在的文件:PcMessageHandler.cs 中的Initialize函數

2、數據讀取及恢復

void Load_Gadget()

{

    Thread.Sleep(3000); //wait 3s

     try

    {

        if (!GadgetCache.OnlineFlag)

         {

            Globals.YFShowInfo("Load ...", "Load_Gadget", Globals.YFInfoType.Level_8);

            GadgetCache.RunFlag = true;

            string[] AppIds = GadgetCache.EnumApps();

             byte[] bytData = null;

            foreach (string AppId in AppIds)

            {

                if (GadgetCache.OnlineFlag)

                {

                     GadgetCache.RunFlag = false;

                     return;

                }

                GadgetCache.LoadApp(AppId, out bytData);

                ProcessMessage(GadgetCache.ToAuxMessage(269, bytData));

                 string[] ContentIds = GadgetCache.EnumContentItems(AppId);

                 foreach (string ContentId in ContentIds)

                 {

                    if (GadgetCache.OnlineFlag)

                     {

                        GadgetCache.RunFlag = false;

                        return;

                    }

                     GadgetCache.LoadContentItem(AppId, ContentId, out bytData);

                     ProcessMessage(GadgetCache.ToAuxMessage(276, bytData));

                 }

            }

            GadgetCache.RunFlag = false;

            Globals.YFShowInfo("End", "Load_Gadget", Globals.YFInfoType.Level_8);

        }

    }

    catch

    {

        GadgetCache.RunFlag = false;

         Globals.YFShowInfo("Load ...Error", "Load_Gadget", Globals.YFInfoType.Level_8);

    }

}

代碼所在的文件:PcMessageHandler.cs 中的PcMessageHandler類

4、其它說明

Sideshow SDK自帶的Sideshow模擬器竟然不支持文件系統,所以為了便於調試(在硬件平台上測試是 很費時間的),我又擴展了我的MF模擬器,讓它也可以支持Sideshow了,不過唯一不爽的是,添加該功能 後,以後所有的MF應用程序必須要求VS2008具有管理員權限。

好處是我的MF模擬器可以模擬Sideshow設備連線和掉線,這一點官方的Sideshow模擬器是不支持的, 有了這個功能,我才方便測試我的Gadget本地恢復。

這是非聯機模式,注意Sideshow界面的右上角沒有系統聯機的狀態信息,此外,仔細看,一些非本地 Gadget也出現在界面中的了,這時它們的操作和聯機一樣。

這是聯機模式,此時出現的Gadget是Sideshow控制面板選中的Gadget。注意界面的右上角出現了聯機 狀態。

說明:Sideshow連接中的COM僅僅是一個通道借用,目的是采用串口的操作函數進行數據讀寫,其實物 理串口並沒有數據。標准Sideshow模擬器連接的是COM33,我的模擬器和實際設備一致,選用的是COM3。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved