CSharp Tips:讓DotNet實現的COM物件支援IObjectSafety介面 (轉)
CSharp Tips:讓DotNet實現的COM物件支援IObjectSafety介面 (轉)[@more@]
當我們實現的COM,或者在中的時候,往往會出現警告框,提示不的控制元件正在執行。這是因為瀏覽器安全策略所限定的,瀏覽器認為只有“安全的物件”才能夠被。
所謂安全的物件就是指那些不訪問本地資源的物件,例如不會去讀登錄檔,不會寫等等。一個滿足條件的物件透過支援ISafety介面告訴瀏覽器,自己是合法的。
下面就簡單的介紹一下怎麼在中實現對於IObjectSafety介面的支援。
思路
C/C++d的可以直接在SDK中找到IObjectSafety的定義,所以需要支援的話非常容易。C#比較麻煩,因為我們沒有辦法獲得IObjectSafety的定義,不過沒有問題,我們可以按照IObjectSafety在SDK中的定義,在C#的工程中重新定義該介面。
如果大家瞭解COM機制一定會知道,所謂藉口的定義之出現在型別庫中,與實現無關。而判斷一個介面唯一性就是定義介面時指定的UUID。此外自己重新定義時需要保證介面中沒有的引數與返回值必須與原定義一致即可。
我們的做法就是,找到ObjSafe.idl,然後複製其中的UUID,利用這個UUID在C#中定一個interface IObjectSafety,並且申明其中的兩個函式;定義完成之後,讓需要檢查安全介面的繼承該介面,並在該元件內部實現IObjectSafety的兩個函式,按照要求做適當的返回,那麼用這個元件包裝的COM物件在IE中呼叫就被認為是安全的了。
第一次嘗試
按照上面的思路,我們開始進行嘗試
idl中的介面定義
[
object,
uuid(CB5BDC81-93C1-11cf-8F20-00805F2CD064),
pointer_default(unique)
]
interface IObjectSafety : IUnknown
{
HRESULT GetInterfaceSafetyOptions(
[in] REFIID riid, // Interface that we want options for
[out] D * pdwSupportedOptions, // Options meaningful on this interface
[out] DWORD * pdwEnabledOptions); // current option values on this interface
object,
uuid(CB5BDC81-93C1-11cf-8F20-00805F2CD064),
pointer_default(unique)
]
interface IObjectSafety : IUnknown
{
HRESULT GetInterfaceSafetyOptions(
[in] REFIID riid, // Interface that we want options for
[out] D * pdwSupportedOptions, // Options meaningful on this interface
[out] DWORD * pdwEnabledOptions); // current option values on this interface
HRESULT SetInterfaceSafetyOptions(
[in] REFIID riid, // Interface to set options for
[in] DWORD dwOptionSetMask, // Options to change
[in] DWORD dwEnabledOptions); // New option values
}
[in] REFIID riid, // Interface to set options for
[in] DWORD dwOptionSetMask, // Options to change
[in] DWORD dwEnabledOptions); // New option values
}
IObjectSafety介面定義
因為介面中存在指標,所以直接採用Int32的整型形式,用到了unsafe code。
[Guid("CB5BDC81-93C1-11cf-8F20-00805F2CD064")]
public interface IObjectSafety
{
// methods
unsafe void GetInterfacceSafyOptions(
System.Int32 riid,
System.Int32* pdwSupportedOptions,
System.Int32* pdwEnabledOptions);
void SetInterfaceSafetyOptions(
System.Int32 riid,
System.Int32 dwOptionsSetMask,
System.Int32 dwEnabledOptions);
}
繼承
public interface IObjectSafety
{
// methods
unsafe void GetInterfacceSafyOptions(
System.Int32 riid,
System.Int32* pdwSupportedOptions,
System.Int32* pdwEnabledOptions);
void SetInterfaceSafetyOptions(
System.Int32 riid,
System.Int32 dwOptionsSetMask,
System.Int32 dwEnabledOptions);
}
繼承
public class MyControl : System..Forms.UserControl,IObjectSafety
實現
// implement functions of IObjectSafety
public unsafe void GetInterfacceSafyOptions(System.Int32 riid,System.Int32* pdwSupportedOptions,System.Int32* pdwEnabledOptions)
{
public unsafe void GetInterfacceSafyOptions(System.Int32 riid,System.Int32* pdwSupportedOptions,System.Int32* pdwEnabledOptions)
{
...
}
public void SetInterfaceSafetyOptions(System.Int32 riid,System.Int32 dwOptionsSetMask,System.Int32 dwEnabledOptions)
{
}
public void SetInterfaceSafetyOptions(System.Int32 riid,System.Int32 dwOptionsSetMask,System.Int32 dwEnabledOptions)
{
...
}
}
一切正常編譯透過,但是透過IE呼叫測試頁面,在裝載頁面的時候卻產生了一個關閉應用程式異常,仔細察看內容Error Report是的地址訪問。無語中...
第二次嘗試
由於是非法的記憶體地址訪問,很自然的聯想到是介面定義的問題,因為存在unsafe code,查查文件發現根本無需使用unsafe code這麼誇張,可以透過out這個引數修飾符解決。
修改定義和實現如下
IObjectSafety介面定義
[Guid("CB5BDC81-93C1-11cf-8F20-00805F2CD064")]
public interface IObjectSafety
{
// methods
void GetInterfacceSafyOptions(
System.Int32 riid,
out System.Int32 pdwSupportedOptions,
out System.Int32 pdwEnabledOptions);
void SetInterfaceSafetyOptions(
System.Int32 riid,
System.Int32 dwOptionsSetMask,
System.Int32 dwEnabledOptions);
}
public interface IObjectSafety
{
// methods
void GetInterfacceSafyOptions(
System.Int32 riid,
out System.Int32 pdwSupportedOptions,
out System.Int32 pdwEnabledOptions);
void SetInterfaceSafetyOptions(
System.Int32 riid,
System.Int32 dwOptionsSetMask,
System.Int32 dwEnabledOptions);
}
實現
// implement functions of IObjectSafety
public unsafe void GetInterfacceSafyOptions(System.Int32 riid,out System.Int32 pdwSupportedOptions,out System.Int32 pdwEnabledOptions)
{
public unsafe void GetInterfacceSafyOptions(System.Int32 riid,out System.Int32 pdwSupportedOptions,out System.Int32 pdwEnabledOptions)
{
...
}
public void SetInterfaceSafetyOptions(System.Int32 riid,System.Int32 dwOptionsSetMask,System.Int32 dwEnabledOptions)
{
}
public void SetInterfaceSafetyOptions(System.Int32 riid,System.Int32 dwOptionsSetMask,System.Int32 dwEnabledOptions)
{
...
}
編譯透過,不錯;IE呼叫測試頁面,同樣的錯誤!鬱悶,無鬥志,回家。
}
編譯透過,不錯;IE呼叫測試頁面,同樣的錯誤!鬱悶,無鬥志,回家。
第三次嘗試
睡了一覺,飽餐戰飯,繼續思考。
自己比較了生成的型別庫,發現一些很奇怪的現象,在型別庫中IObjectSafety居然被定義了兩次interface IObjectSafety : IUnknown,以及dispinterface IObjectSafety : IDispatch。而偏偏MyControl是從dispinterface IObjectSafety上繼承的。這就與正確的IObjectSafety的介面說明相違背,問題應該出在這裡。
MSDN,查文件。System.Runtime.InteropService下有很多關於描述介面的屬性,從中可以找到產生問題的原因。有一個屬性InterfaceTypeAttribute,就是用來說明定義的介面是從IUnknown繼承還是IDispatch繼承,預設情況下是Dual的,所以是兩份。
再次定義如下:
[Guid("CB5BDC81-93C1-11CF-8F20-00805F2CD064"),InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IObjectSafety
{
// methods
void GetInterfacceSafyOptions(
System.Int32 riid,
out System.Int32 pdwSupportedOptions,
out System.Int32 pdwEnabledOptions);
void SetInterfaceSafetyOptions(
System.Int32 riid,
System.Int32 dwOptionsSetMask,
System.Int32 dwEnabledOptions);
}
其餘程式碼不變,重新編譯,透過;察看匯出型別庫,果然少了很多垃圾;呼叫測試頁面,正確。激動中...
public interface IObjectSafety
{
// methods
void GetInterfacceSafyOptions(
System.Int32 riid,
out System.Int32 pdwSupportedOptions,
out System.Int32 pdwEnabledOptions);
void SetInterfaceSafetyOptions(
System.Int32 riid,
System.Int32 dwOptionsSetMask,
System.Int32 dwEnabledOptions);
}
其餘程式碼不變,重新編譯,透過;察看匯出型別庫,果然少了很多垃圾;呼叫測試頁面,正確。激動中...
怎樣讓IE認為你的物件安全
實現了這個介面,剩下的事情就很簡單了。前面提到過如果按照正規的途徑你需要確保你的程式碼沒有訪問系統的本地自然,然後按照文件要求,當該物件被不同的介面呼叫查詢的時候,做不同的反饋。具體實現可以在MSDN的Sample中找到。
當然我們可以寫一個物件讀寫本地檔案,但是支援IObjectSafety介面,並且始終宣告自己是合法的,這樣來欺騙瀏覽器,那麼程式碼就很簡單了,如下:
// implement functions of IObjectSafety
public void GetInterfacceSafyOptions(System.Int32 riid,out System.Int32 pdwSupportedOptions,out System.Int32 pdwEnabledOptions)
{
pdwSupportedOptions = CLsObjectSafety.INTERFACESAFE_FOR_UNTRUSTED_CALLER;
pdwEnabledOptions = CLsObjectSafety.INTERFACESAFE_FOR_UNTRUSTED_DATA;
}
public void SetInterfaceSafetyOptions(System.Int32 riid,System.Int32 dwOptionsSetMask,System.Int32 dwEnabledOptions)
{
}
只要這麼些,就不會再有討厭的對話方塊彈出了。
public void GetInterfacceSafyOptions(System.Int32 riid,out System.Int32 pdwSupportedOptions,out System.Int32 pdwEnabledOptions)
{
pdwSupportedOptions = CLsObjectSafety.INTERFACESAFE_FOR_UNTRUSTED_CALLER;
pdwEnabledOptions = CLsObjectSafety.INTERFACESAFE_FOR_UNTRUSTED_DATA;
}
public void SetInterfaceSafetyOptions(System.Int32 riid,System.Int32 dwOptionsSetMask,System.Int32 dwEnabledOptions)
{
}
只要這麼些,就不會再有討厭的對話方塊彈出了。
如果你的元件是在客戶端,在瀏覽器中呼叫,那麼所有的工作已經完成;所以是希望透過Codebase的方式釋出,你還需要去搞一個數字簽字,已經不是本文討論的範圍了,就到這裡,結束了。
參考文件
1、HOWTO: Implement IObjectSafety in Controls(.com/default.x?scid=kb;EN-US;q182598">)
2、Exposing Components to (/html/cpconexposietframeworkcomponentstocom.asp">)
3、System.Runtime.InteropServices()
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752019/viewspace-962632/,如需轉載,請註明出處,否則將追究法律責任。
請登入後發表評論
登入
全部評論
相關文章
- 利用wps的com口用python實現excel轉pdfPythonExcel
- Lock物件Condition介面實現等待/通知物件
- dotnet 委託的實現解析
- Metasploit技巧命令支援tips
- 【轉】【譯】讓你的網站更炫酷的一些小 tips網站
- JAVA 將介面的引用指向實現類的物件Java物件
- DotNet Dictionary 實現簡介
- keycloak~正確讓api介面支援跨域API跨域
- .net webapi 實現 介面版本控制並打通swagger支援WebAPISwagger
- 高效能USB轉串列埠介面卡,讓USB和序列介面輕鬆實現雙向通訊!串列埠
- DDD的實體、值物件、聚合根的基類和介面:設計與實現物件
- JS實現JSON物件與URL引數的相互轉換JSON物件
- C#動態建立介面的實現例項物件C#物件
- dotnet 9 WPF 連字元渲染支援字元
- Dotnet Core多版本API共存的優雅實現API
- .NET Core CSharp初級篇 1-3物件導向CSharp物件
- 讓 @HystrixCommand 支援Spring EL實現動態更新commandKey,groupKey,threadPoolKeySpringthread
- 怎麼把ppt轉成word?讓你快速實現ppt轉word的教程
- help.hybris.com和help.sap.com網站的搜尋實現網站
- 關於應該實現ActionListener介面還是使用ActionListener的匿名類物件物件
- python 介面實現類的Python
- delphi 判斷類是否實現介面,獲取類實現的介面
- 在dotnet core實現類似crontab的定時任務
- node 本地伺服器實現前端介面代理,轉發伺服器前端
- Flutter頁面跳轉到IOS原生介面 如何實現?FlutteriOS
- .NET Core CSharp初級篇 1-5 介面、列舉、抽象CSharp抽象
- [轉帖]10 Tips for using the Eclipse Memory AnalyzerEclipse
- CATIA是為支援企業實現數字化轉型
- vue實現物件的複製Vue物件
- Java 中的物件池實現Java物件
- Java 物件實現 Serializable 的原因Java物件
- vs2019 Com元件初探-通過IDispatch介面呼叫Com元件
- Android開發實現連續跳轉幾個介面後在最後一個介面完美跳回最初的介面Android
- 10分鐘實現dotnet程式在linux下的自動部署Linux
- CSharp詳解CSharp
- [譯]JS Tips:選擇(picking)和反選(rejecting)物件的屬性JS物件
- vs2019 Com元件初探-簡單的COM編寫以及實現跨語言呼叫元件
- 介面 做具體的實現
- Swift-Tips之整數轉陣列Swift陣列