1.平台互操作性和不安全的**:c#功能強大,但有些時候,它的表現仍然有些「力不從心」,所以我們只能摒棄它所提供的所有安全性,轉而退回到記憶體位址和指標的世界。
c#通過3種方式對此提供支援。
(1)第一種方式是通過平台呼叫(platform invoke,p/invoke)來呼叫非託管**dll所公開的api。
(2)第二種方式是通過不安全的**,它允許我們訪問記憶體指標和位址。很多情況下,**需要綜合運用這兩種方式。
(3)第三種方式是通過com interop(com互操作)。
2.平台呼叫:
(1)外部函式的宣告:確定了要呼叫的目標函式以後,p/invoke的下一步便是用託管**宣告函式,和普通方法一樣,必須在乙個類中宣告目標api,但要為它新增extern修飾符,從而把它宣告為外部函式,extern方法始終是靜態方法,因此不包含任何實現。相反,附加在方法宣告之前的dllimport特性指向實現。該特性需要定義該函式的dll的「名稱」,匯入的dll必須在路徑內,其中包含可執行檔案的目錄,以使其能夠載入成功。「執行時」根據方法名來判斷函式名,然而也可以用entrypoint具名引數來重寫預設行為,明確提供乙個函式名。
(2)引數的資料型別:在確定目標dll和匯出函式,那麼要標識或建立與外部函式中的非託管資料型別對應的託管資料型別。
3.為順序布局使用structlayoutattribute:有些api涉及的型別沒有對應的託管型別,要呼叫這些api,需要託管**重新宣告型別。例如,可以使用託管**來宣告非託管的colorref struct,如colorref結構清單。**中宣告的關鍵之處在於structlayoutattribute,預設情況下,託管**可以優化型別的記憶體布局,所以,記憶體布局可能不是從乙個欄位到另乙個字段順序儲存。為了強制順序布局,使型別能夠直接對映,而且可以在託管和非託管**之間逐位地複製,你需要新增structlayoutattribute特性,並指定layoutkind.sequential列舉值。
4.平台呼叫(p/invoke)的錯誤處理:win32 api程式設計的乙個不便之處在於,錯誤經常以不一致的方式來報告,如有api返回0、1、false等,有api以out引數來處理,非託管**中的win32錯誤報告很少通過異常來生成。p/invoke設計者為此提供了相應的處理機制,要啟用這一機制,dllimport特性的setlasterror具名引數要設為true,這樣就可以例項化乙個system.componentmodel.win32exception。在p/invoke呼叫之後,會自動用win32錯誤資料來初始化它,如virtualmemorymanger類的**清單。這樣一來,開發人員就可以提供每個api使用的自定義錯誤檢查,同時仍然可以使用一種標準方式來報告錯誤。
5.使用safehandle:很多時候,p/invoke會涉及乙個資源,比如視窗控制代碼(window handle),等等。在用完此類資源之後,**需要清理它們。但是,不要強迫開發人員記住這一點,並每次都人工編寫**,而是應該提供實現idisposable介面和終結器的類。為了對此提供內建的支援,如下面的virtualmemoryptr類,該類派生自system.runtime.interopservices.safehandle。safehandle類包含兩個抽象成員:isinvalid和releasehandle()。在後者中,你可以放入對資源進行清理的**,前者則指出是否執行了資源清理**。可檢視virtualmemoryptr類**清單。
6.p/invoke指導原則:
(1)核實確實沒有託管型別已經公開你想要的api。
(2)將api外部方法定義為private,或者在簡單的情況下定義為internal。
(3)圍繞外部方法提供公共包裝方法,執行資料型別轉換和錯誤處理。
(4)過載包裝方法,並通過為外部方法呼叫插入預設值,減少所需的引數數目。
(5)在宣告api的同時,使用enum或const為api提供常量值。
(6)針對支援getlasterror()的所有p/invoke方法,務必將setlasterror命名特性的值設為true。這樣一來,就可以通過system.componentmodel.win32exception報告錯誤。
(7)將控制代碼之類的資源包裝,包裝在從system.runtime.interopservices.safehandle派生或者支援idisposable的類中。
(8)非託管**中的函式指標對映到託管**中的委託例項。通常,這需要宣告乙個特定的委託型別,它與非託管函式指標的簽名是匹配的。
(9)將輸入/輸出引數和輸出引數對映到ref引數,而不是依賴於指標。
7.不安全的**:可以使用unsafe用作型別或者型別內部的特定成員的修飾符。unsafe修飾符對生成的cil**本身沒有影響。它只是乙個預編譯指令,作用是向編譯器指明允許在不安全的**塊內操作指標和位址。
8.指標的宣告:由於指標(本身只是恰好指向記憶體位址的一些整形值)不會被垃圾**,所以c#不允許非託管型別之外的被引用物型別。換言之,型別不能是引用型別,不能是泛型型別,而且內部不能包含引用型別。如 byte* pdata;指標是一種全新的型別,和結構、列舉、類不同,指標的終極基類不是system.object,甚至不能轉換成system.object,相反,它們能轉換成system.intptr(後者能轉換成system.object)。
9.指標的賦值:我們需要使用位址運算子(&)來獲取值型別的位址。無論哪種方法,為了將一些資料的位址賦值給乙個指標,要求如下。
(1)資料必須屬於乙個變數。
(2)資料必須是乙個非託管型別。
(3)變數需要用fixed固定,不能移動。
如 byte* pdata = &bytes[0];//編譯錯誤,資料可能發生移動,需要固定。
如 byte bytes = new bytes[24]; fixed (byte* pdata = &bytes[0]){}//編譯正確
10.指標的解引用:為了訪問指標引用的乙個型別值,要求你解引用指標,即在指標型別之前新增乙個間接定址運算子*。如 byte data = *pdata;不能對void*型別的指標應用解引用運算子,void*資料型別代表的是指向乙個未知型別的指標。由於資料型別未知,所以不能解引用到另一種型別。相反,為了訪問void*引用的資料,必須把它轉換成其他任何指標型別的變數,然後對後一種型別執行解引用。
[structlayout(layoutkind.sequential)]view codepublic
struct
colorref
}public
class
virtualmemorymanger
uint lpfloldprotect = 0
;
if (!virtualprotectex(hprocess, codebytesptr, (intptr)size, (uint)protectionoptions.pageexecutereadwrite, ref
lpfloldprotect))
return
codebytesptr;
}public
static intptr allocexecutionblock(int
size)
public
static
bool
virtualfreeex(intptr hprocess, intptr lpaddress, intptr dwsize)
return
result;
}public
static
bool
virtualfreeex(intptr lpaddress, intptr dwsize)
}public
class
virtualmemoryptr:safehandle
public
static
implicit
operator
intptr(virtualmemoryptr virtualamemorypointer)
protected
override
bool
releasehandle()
return
true
; }
public
override
bool isinvalid }
}[flags]
public
enum
allocationtype
[flags]
public
enum
protectionoptions
[flags]
public
enum
memoryfreetype
c 學習筆記(15)
讀檔案 讀檔案與寫檔案步驟相似,但是讀取方式相對於比較多 步驟如下 1.包含標頭檔案 include 2.建立流物件 ifstream ifs 3.開啟檔案並判斷檔案是否開啟成功 ifs.open 檔案路徑 開啟方式 4.讀資料 四種方式讀取 5.關閉檔案 ifs.close include voi...
引用(C 學習筆記 15)
一 引用的作用 建立引用的作用是為變數另起乙個名字,變數的引用通常被認為是變數的別名。對變數宣告乙個引用,並不另外開闢記憶體單元,變數 i 和引用 j 占用記憶體的同一位置,當 i 變化時,j 也隨之變化,反之亦然。二 引用的格式 型別 引用名 已定義的變數名 注意 1 在宣告引用時,必須立即對它進...
學習筆記15
響應式 media 不同的大小 執行不行的css 寫上 float left 預設不會屏佔百分百,寫上多少就是多少 但是無法滿足全屏鋪滿 min left 900x 的意思是 當寬度小於這個值時候 底部出現滾動條 position absolute 這麼寫 會鋪滿螢幕 只有加上 left right...