在windows phone Mango中使用原生代碼開發程序


    本文不討論創建可執行的exe程序,主要想說明怎么在silverlight程序里面調用由原生代碼所編寫的DLL(C++ / ARM).

    原生代碼可以調用更多的API,但是這並不是說你就能隨意獲得那些你沒有權限的資源,比如,你可以使用CopyFile這個API,但是如果你試圖把文件Copy到\Windows文件夾,就會得到一個0x4ec的錯誤代碼,系統會禁止你這樣做.所以,你的程序也只能在沙箱的環境下運行.

    本文中所涉及的知識包含 C++,COM交互,Windows phone 程序設計.希望你在開發你的程序前能保證熟悉這些技術.因為原生代碼還不能調試,所以你只能使用返回錯誤信息的方式來確保你的程序能正確運行.

    需要注意的是: 如果你有些任務需要執行很長時間,它們在調試的時候能很好的運行,但是在實際運行的時候,你最好采用一個線程來做這些事情.因為在非調試狀態下檢測程序會檢測你的程序,一但你的程序鎖定超過10秒,那么系統會自動退出這個程序.

   有人建議原生代碼所寫的DLL需要簽名,其實這並不是必須的.在Mango設備里面可以使用未簽名的庫.

   討論一下互操作鎖.詳細討論可以參見這個貼子.互操作鎖在WP7.5里面出現.最直觀的表現就是你的程序如果使用了ID_CAP_INTEROPSERVICES,那么所使用的設備必須得解鎖.

   下面就是一個詳細的操作步驟:

 PS: 所需要的軟件請點擊名稱下載

   1. 安裝 Visual Studio 2008 及 最新的補丁包,確保安裝 C++.

   2. 安裝 Windows Modile 6 Professional SDK Resfresh.

   3. 安裝 Visual Studio 2010 和 最新的補丁包.

   4. 安裝 Windows Phone SDK 7.1

   5. 下載 Microsoft.Phone.InteropServices.zip. 下載解壓后要確定文件是非鎖定狀態,解鎖可以按以下操作,文件是點擊右鍵,選擇屬性,點擊解鎖.

   6. 把Microsoft.Phone.InteropServices.dll放到  C:\Program Files\Reference Assemblies\Microsoft\Framework\Silverlight\v4.0\Profile\WindowsPhone71 ,如果是64位系統就放到 C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\Silverlight\v4.0\Profile\WindowsPhone71.

   7. 打開 Visual Studio 2010 的命令行工具,轉到Microsoft.Phone.InteropServices.dll放置的地方,輸入以下代碼,請確定注冊成功.否則引用這個DLL時會報沒有引用命名.

SN -Vr Microsoft.Phone.InteropServices.dll

 8. 在DLL的目錄下有一個RedistList文件夾,里面有一FrameworkList.xml,加下面代碼

<File AssemblyName="Microsoft.Phone.InteropServices" Version="7.0.0.0" Culture="neutral" ProcessorArchitecture="MSIL" InGac="false" />

 9.  安裝 zune

   10. 打開 VS2008,創建新項目.

   11. 選擇 Visual C++ / Smart Device / ATL Smart Device 項目,不能選擇MFC.

   12. 點擊下一步

   13. 取消 Pocket PC 2003,加入 Windows Mobile 6 Pro SDK,點擊下一步

   14. 點擊完成

   15. 編譯設置為 Release.

   16. 在工程屬性 / 屬性配置 / C/C++ / 預處理 / 預處理定義里面加入 

_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA

 17. 在工程里面加入一個新類 , 選擇 "Simple ATL object"

   18. 對話框內 "Short name"是 Com類的名字,其他可以保持默認,點擊完成.

   19. 文件添加就完成了.包含這些文件 : 頭文件(.h) ,代碼文件 (.cpp) , Com定義文件(.idl), Com類的頭文件(.h),Com類的代碼文件(.cpp).

   20. 把Com類的基類改成 IUnknown.

   21. 在Com類的頭文件中,刪除下面這一句

COM_INTERFACE_ENTRY(IDispatch)

 22. 在IDL文件中,把IDispatch改成IUnknown.

   23. 現在可以向你的Com類加入方法了.所有方法都必須以HRESULT為返回值.這個值用來判斷函數是否執行成成功.成功可以返回 S_OK,如果有錯誤代碼,則把錯誤代碼與0x80070000進行邏輯或的結果做為返回值.如果你想返回一個變量,你需要在IDL文件里面聲明他.參數以COM為邊界,參見這里這里查看COM支持的參數類型.

   24. 在COM類中加入如下代碼:

 1 STDMETHODIMP CNative::TestMethod1()
2 {
3 BOOL result = ::CopyFile(L"\\Windows\\0000_System.Windows.xaml", L"\\Windows\\Test.xaml", TRUE); //這里會拋出一個異常
4 if (result)
5 return S_OK;
6 else
7 return 0x80070000 | ::GetLastError();
8 }
9 STDMETHODIMP CNative::TestMethod2(BSTR InputString, BSTR* OutputString)
10 {
11 size_t size = 1000; // in chars
12 TCHAR* msg = new TCHAR[size];
13 wcscpy_s(msg, size, L"\0");
14
15 LPWSTR value = new WCHAR[20];
16
17 _itow((int)wcslen(InputString), value, 10);
18 wcscat_s(msg, size, L"Length of string is: ");
19 wcscat_s(msg, size, value);
20
21 *OutputString = SysAllocString(msg);
22
23 delete[] msg;
24 delete[] value;
25
26 return S_OK;
27 }

 25. Com類的頭文件中加入下面代碼,放在END_COM_MAP()后面

1 STDMETHOD(TestMethod1)();
2 STDMETHOD(TestMethod2)(BSTR InputString, BSTR* OutputString);

 26. 在IDL文件里面加如如下代碼,關於參數定義,可以查看 點擊我吧

1 HRESULT TestMethod1();
2 HRESULT TestMethod2(BSTR InputString, BSTR* OutputString);

 27. 記下IDL文件里面的接口GUID(uuid標識),類標識GUID.

   28. 在VS2010里面創建一個新的WP工程.

   29. VS2008里面編譯生成DLL,然后把DLL拷貝到WP工程目錄下.

   30. 在WP工程下創建WPInteropManifest.xml文件,內容為

1 <?xml version="1.0" encoding="UTF-8"?>
2 <Interop>
3 </Interop>

  31. 更改WPInteropManifest.xml文件的編譯規則為"Content","Copy if newer".

  32. 更改COM輸出的DLL編譯規則為"Content","Copy if newer"

  33. WP工程添加引用"Microsoft.Phone.InteropServices"

  34. 打開WMAppManifest.xml文件,添加

<Capability Name="ID_CAP_INTEROPSERVICES" />

  35. 添加一個代碼文件 輸入以下內容:

 

 1 using System.Runtime.InteropServices;
2
3 [ComImport, ClassInterface(ClassInterfaceType.None), Guid("YOUR-COCLASS-GUID-GOES-HERE")]
4 public class CNative
5 {
6 }
7
8 [ComImport, Guid("YOUR-INTERFACE-GUID-GOES-HERE"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
9 public interface INative
10 {
11 void TestMethod1();
12 [return : MarshalAs(UnmanagedType.BStr)]
13 string TestMethod2([MarshalAs(UnmanagedType.BStr)] string InputString);
14 }

   36.創建一個測試代碼文件,輸入以入內容

 1 uint retval = Microsoft.Phone.InteropServices.ComBridge.RegisterComDll("Your Com DLL.dll", new Guid("YOUR-COCLASS-GUID-GOES-HERE"));
2 INative MyNativeCodeInstance = (INative)new CNative();
3 string result1 = "OK";
4 try
5 {
6 MyNativeCodeInstance.TestMethod1(); //這里拋出一個異常
7 }
8 catch (Exception ex)
9 {
10 result1 = ex.Message;
11 }
12 string result2 = MyNativeCodeInstance.TestMethod2("Hello, Mango!");
13 MessageBox.Show(result1 + Environment.NewLine + result2);

   37. 運行程序,測試代碼.

   38. 注意,當使用高級功能時.我們需要Marshal-class,比如操作內存等.此時需要使用Microsoft.Phone.InteropServices內的Marshal類,如果使用System.Runtime.InteropServices命名空間下的此類,會拋出一個MethodAccessException異常.

   關於簡單的調用方法就說到這里.希望大家都能搞出更好的自制程序.如果翻譯或者描述有不准確的地方,希望大家指正,謝謝!!

原貼地址: http://forum.xda-developers.com/showthread.php?t=1299134


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM