.NET(C#) 平台叫用:不依賴平台的GetWindowLongPtr和SetWindowLongPtr API

來源:互聯網
上載者:User

首先在方法聲明上,由於在32位Windows上GetWindowLongPtr和SetWindowLongPtr僅僅是宏定義,不是具體函數,所以只能去使用GetWindowLong和SetWindowLongPtr函數。因此我們需要定義兩份這樣的函數。其次是參數在不同環境下的變化。比如GetWindowLang的函數原型:

LONG WINAPI GetWindowLong(

  __in  HWND hWnd,

  __in  int nIndex

);

 

它是返回LONG的。而GetWindowLongPtr的函數原型:

LONG_PTR WINAPI GetWindowLongPtr(

  __in  HWND hWnd,

  __in  int nIndex

);

 

它是返回LONG_PTR的。這個LONG_PTR聯通其他的類型比如INT_PTR、UINT_PTR、DWORD_PTR……都是用來使定義好的類型不需要改變就可以輕鬆在32位和64位上的API正確運行。在32位下,它們保持自己的預設大小。在64位下,它們會被擴充成64為下的大小。而注意在.NET下,int永遠是32位的(int僅僅是System.Int32類型的別名),而long(System.Int64類型)永遠是64位的,因此我們只能用依賴平台大小的IntPtr來表示上述資料類型。

 

那麼首先把這四個API都聲明一下:

[DllImport("user32.dll", EntryPoint = "GetWindowLong")]

static extern IntPtr GetWindowLong32(IntPtr hWnd, int nIndex);

 

[DllImport("user32.dll", EntryPoint = "GetWindowLongPtr")]

static extern IntPtr GetWindowLong64(IntPtr hWnd, int nIndex);

 

[DllImport("user32.dll", EntryPoint = "SetWindowLong")]

static extern IntPtr SetWindowLong32(IntPtr hWnd, int nIndex, IntPtr dwNewLong);

 

[DllImport("user32.dll", EntryPoint = "SetWindowLongPtr")]

static extern IntPtr SetWindowLong64(IntPtr hWnd, int nIndex, IntPtr dwNewLong);

 

接著用專門的方法判斷是32位還是64位執行環境,然後根據環境調用相應的本地API。

//WindowLongFlags的定義可以參考:http://www.pinvoke.net/default.aspx/Enums/WindowLongFlags.html

 

public static IntPtr GetWindowLongPtr(IntPtr hWnd, WindowLongFlags nIndex)

{

    if (IntPtr.Size == 8)

        return GetWindowLong64(hWnd, (int)nIndex);

    else

        return GetWindowLong32(hWnd, (int)nIndex);

}

 

public static IntPtr SetWindowLongPtr(IntPtr hWnd, WindowLongFlags nIndex, IntPtr dwNewLong)

{

    if (IntPtr.Size == 8)

        return SetWindowLong64(hWnd, (int)nIndex, dwNewLong);

    else

        return SetWindowLong32(hWnd, (int)nIndex, dwNewLong);

}

 

方法定義好後,就可以調用它執行了,不過還有一個問題就是枚舉值的設定,由於對應枚舉對象是依賴平台的,所以把它定義成IntPtr,可是IntPtr對於枚舉值的設定可能會遇到麻煩,可以使用如下方法。

 

首先我們使用這篇文章(.NET(C#):負數位域和正數位域)中的EnumHelper類型,接著定義一個針對基於IntPtr枚舉值的有好封裝類型:IntPtrEnumHelper如下代碼:

static class IntPtrEnumHelper

{

    //判讀是否包含指定標誌位

    public static bool HasFlags(IntPtr val, object flag)

    {

        return EnumHelper.HasFlag(val.ToInt64(), (long)flag);

    }

    //設定標誌位

    public static IntPtr SetFlag(IntPtr val, object flag)

    {

        return new IntPtr(EnumHelper.SetFlag(val.ToInt64(), (long)flag));

    }

    //取消標誌位

    public static IntPtr UnsetFlag(IntPtr val, object flag)

    {

        return new IntPtr(EnumHelper.UnsetFlag(val.ToInt64(), (long)flag));

    }

}

 

這樣的話,比如我們想要通過SetWindowLongPtr設定表單的樣式。我們可以直接用上面的方法來對基於IntPtr枚舉對象進行位域的設定或者取消操作。

 

如下封裝代碼:

//WindowLongFlags定義可以參考:http://www.pinvoke.net/default.aspx/Enums/WindowLongFlags.html

 

//設定標誌位

public static IntPtr SetWindowStyles(IntPtr hWnd, WindowStyles ws)

{

    var style = GetWindowLongPtr(hWnd, WindowLongFlags.GWL_STYLE);

    return SetWindowLongPtr(hWnd, WindowLongFlags.GWL_STYLE, IntPtrEnumHelper.SetFlag(style, ws));

}

//取消標誌位

public static IntPtr UnsetWindowStyles(IntPtr hWnd, WindowStyles ws)

{

    var style = GetWindowLongPtr(hWnd, WindowLongFlags.GWL_STYLE);

    return SetWindowLongPtr(hWnd, WindowLongFlags.GWL_STYLE, IntPtrEnumHelper.UnsetFlag(style, ws));

}

 

代碼下載:

參考這篇文章:.NET(C#):Win32表單API封裝工程

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.