在远程文件查看器里,我们可以很方便地访问设备的文件,但是有一点,双击其中的pe文件并不能直接执行,下面我们将为.Net MF添加这个功能。

默认情况下,.Net MF的用户程序是放在Flash中的BLOCKTYPE_DEPLOYMENT区(参见《Flash远程读写》),只能通过VS2008进行部署。TinyCLR启动后,直接从Flash的BLOCKTYPE_DEPLOYMENT区的加载应用程序,由于这样的设计,所以在Flash上仅能存放一个用户程序。

.Net MF已经支持了文件系统,并且我们实现了远程文件查看器,理论上只要空间足够,我们能放若干个用户程序,这样问题就来了,我们能否任意执行文件系统中的pe文件?

.Net MF系统中的可执行文件或模块,其扩展名并不是exe或dll,统一为pe,唯一不同是,可执行的pe文件中含有启动入口标识。pe文件是exe和dll经过MetaDataProcessor.exe文件再加工而来。

实现思路其实很简单:第一、分别把不同的用户程序,放到不同目录中去;第二、在根目录建立一个config.ini纯文本文件,里面有一条记录:Startup=\xxx,标识启动项;第三、修改TinyCLR代码,让其从config.ini中的指定目录处加载用户程序。

 TinyCLR中的Code修改如下(CLRStartup.cpp文件),枚举指定目录中的pe文件,并加载之。

  1.  HRESULT LoadDeploymentAssemblies()  
  2.  
  3.  {  
  4.  
  5.      TINYCLR_HEADER();  
  6.  
  7.    
  8.  
  9.      WCHAR current_file[256];  
  10.  
  11.        WCHAR temp_path[256];  
  12.  
  13.      UINT32 findHandle=NULL;   
  14.  
  15.        FileSystemVolume* volume = NULL;  
  16.  
  17.      STREAM_DRIVER_INTERFACE*  streamDriver=volume->m_streamDriver;  
  18.  
  19.        HRESULT ret;  
  20.  
  21.    
  22.  
  23.      volume = FileSystemVolumeList::GetFirstVolume();  
  24.  
  25.        if(volume ==NULL)  
  26.  
  27.        {  
  28.  
  29.             TINYCLR_SET_AND_LEAVE(CLR_E_FAIL);  
  30.  
  31.        }  
  32.  
  33.        streamDriver=volume->m_streamDriver;  
  34.  
  35.          if(streamDriver==NULL)  
  36.  
  37.        {  
  38.  
  39.             TINYCLR_SET_AND_LEAVE(CLR_E_FAIL);  
  40.  
  41.        }  
  42.  
  43.      //--  
  44.  
  45.      UINT32 rHandle = NULL;    
  46.  
  47.       if(streamDriver->Open(&volume->m_volumeId, L"\\config.ini", &rHandle) == S_OK && rHandle != NULL)  
  48.  
  49.        {             
  50.  
  51.               INT64 FileSize;  
  52.  
  53.               int bytesread=0;  
  54.  
  55.             streamDriver->GetLength(rHandle,&FileSize);  
  56.  
  57.                 if(FileSize>510 || FileSize<20)  
  58.  
  59.                 {  
  60.  
  61.                      streamDriver->Close(rHandle);   
  62.  
  63.                 if(FileSize == 0)  debug_printf("Can't find config.ini!\r\n");  
  64.  
  65.                      else debug_printf("Load Application failed(2)!\r\n");  
  66.  
  67.                   TINYCLR_SET_AND_LEAVE(CLR_E_FAIL);  
  68.  
  69.                 }             
  70.  
  71.          if(streamDriver->Read(rHandle, (BYTE *)temp_path,(INT32)FileSize ,&bytesread) != S_OK && bytesread!=(UINT32)FileSize)  
  72.  
  73.              {  
  74.  
  75.                     streamDriver->Close(rHandle);    
  76.  
  77.                  debug_printf("Load Application failed(3)!\r\n");  
  78.  
  79.                  TINYCLR_SET_AND_LEAVE(CLR_E_FAIL);  
  80.  
  81.              }  
  82.  
  83.              streamDriver->Close(rHandle);             
  84.  
  85.    
  86.  
  87.              if(temp_path[0]!=0xFEFF || temp_path[8]!=0x3D)  
  88.  
  89.              {  
  90.  
  91.                  TINYCLR_SET_AND_LEAVE(CLR_E_FAIL);  
  92.  
  93.              }  
  94.  
  95.              memcpy(current_file, &temp_path[9],FileSize-9*2 );  
  96.  
  97.              temp_path[FileSize/2-9] = 0;  
  98.  
  99.              for(int i=FileSize/2-10;i>0; i--)  
  100.  
  101.              {  
  102.  
  103.                   if(current_file[i]==0x0D ||current_file[i]==0x0A) current_file[i] = 0;  
  104.  
  105.              }  
  106.  
  107.       }  
  108.  
  109.         else 
  110.  
  111.       {  
  112.  
  113.             TINYCLR_SET_AND_LEAVE(CLR_E_FAIL);  
  114.  
  115.         }  
  116.  
  117.         //--  
  118.  
  119.         ret = volume->FindOpen(current_file,&findHandle);  
  120.  
  121.       if(findHandle==NULL || ret != S_OK)  
  122.  
  123.   {  
  124.  
  125.            TINYCLR_SET_AND_LEAVE(CLR_E_FAIL);      
  126.  
  127.       }    
  128.  
  129.     //--  
  130.  
  131.     FS_FILEINFO findData;  
  132.  
  133.     int pathsize=wcslen(current_file);  
  134.  
  135.       current_file[pathsize++]='\\';  
  136.  
  137.        
  138.  
  139.     findData.FileName=(UINT16 *)&current_file[pathsize];  
  140.  
  141.     findData.FileNameSize = 200;  
  142.  
  143.       memset(findData.FileName,0,(findData.FileNameSize+1)*2);  
  144.  
  145.                
  146.  
  147.       BOOL found=FALSE;   
  148.  
  149.       ret = volume->FindNext(findHandle,&findData,&found);  
  150.  
  151.       while( ret==S_OK && found)  
  152.  
  153.       {        TINYCLR_CHECK_HRESULT(ContiguousBlockAssemblies(volume,current_file));            
  154.  
  155.            memset(temp_path,0,findData.FileNameSize+1);  
  156.  
  157.             ret = volume->FindNext(findHandle,&findData,&found);   
  158.  
  159.       }   
  160.  
  161.     //--  
  162.  
  163.     volume->FindClose(findHandle);       
  164.  
  165.       TINYCLR_NOCLEANUP();             
  166.  
  167. }  
  168.  

远程文件查看器中的代码稍加修改,就能支持双击运行。在双击事件里,一是修改config.ini文件中的运行目录,二是重启TinyCLR,让其加载指定目录中的程序。由于相关代码比较简单,这里就不贴了。

下面来演示一下最终成果。

1、              新建两个.Net MF测试程序,分别命名为Test1、Test2,相关代码如下:

  1. public static void Main()  
  2.  
  3. {  
  4.  
  5. Debug.Print("123456789");  
  6.  
  7. }  
  8.  
  9. public static void Main()  
  10.  
  11. {  
  12.  
  13. Debug.Print("abcdefghijklmn!!!");  
  14.  
  15. }  
  16.  

编译后的pe文件分别为:Test1.pe,Test2.pe

2、              新建config.ini文件(这步可以省略)

3、              通过远程文件查看器,新建两个目录,Test1和Test2,分别拷入Test1.pe和Test2.pe文件。

 

 

4、              分别双击Test1.pe和Test2.pe文件,查看运行结果。