.NET(C#) 平台调用:不依赖平台的GetWindowLongPtr和SetWindowLongPtr API
2012-10-19 13:19
453 查看
http://www.cnblogs.com/mgen/archive/2012/04/09/2439149.html
首先在方法声明上,由于在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封装工程
首先在方法声明上,由于在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封装工程
相关文章推荐
- .NET(C#):Win32窗体API封装工程---Mgen.Interop.WindowLongPtr.cs
- 从.NET平台调用Win32 API(C#调用的dll动态链接库)
- .Net/C# 应用程序直接读取本地 Cookies 文件(WinXP SP2 调用 API: InternetGetCookie 无果)
- 需要事先使用 ApiConfigKit.setThreadLocalApiConfig(apiConfig) 将 ApiConfig对象存入,才可以调用 ApiConfigKit.getApiConf
- 暴强贴:从.NET平台调用Win32 API
- 从.NET平台调用Win32 API
- 暴强贴:从.NET平台调用Win32 API
- 转载暴强贴:从.NET平台调用Win32 API
- 暴强贴:从.NET平台调用Win32 API
- 从.NET平台调用Win32 API
- 从.NET平台调用Win32 API
- 友盟推送 .NET (C#) 服务端 SDK rest api 调用库
- 从.NET平台调用Win32 API
- 转载暴强贴:从.NET平台调用Win32 API
- SetWindowLongPtr和GetWindowLongPtr函数
- C# API 如何保证使用托管对象的平台调用成功
- WinPcap中Pocket.dll里的PacketGetAdapterNames这个API在C#里面的调用
- C# API 如何保证使用托管对象的平台调用成功
- .Net语言 APP开发平台——Smobiler学习日志:如何调用API进行短信发送
- 使用SetWindowLongPtr与GetWindowLongPtr的问题