存档

‘CShap’ 分类的存档

C# 全局快捷键 与接收消息

2009年10月27日 2 条评论

这几天在继续做个Application,用到了 快捷键 ,或者说是 组合键。

费了一天时间来研究这个。在网上找了好多资料都没能成功,连《C#程序开发范例宝典》这本书的第七章第12节的功能快捷键范例都没用,给的源码无法正确应用,让我很失望。
虽然在网上找的那些资料没有能成功运行,但是给我了一些启发,从很多源码中,我找到了以下的结果:

AddMessageFilter (IMessageFilter value)方法 ,

用于添加消息筛选器以便在向目标传送 Windows 消息时监视这些消息。
参数:value : IMessageFilter 接口的实现(就是对象)
警告:向应用程序的消息泵添加消息筛选器会降低性能。

既然接受消息的方法已经找到了,那么接下来就需要一个API来注册快捷键,这个函数为:

[DllImport("user32.dll")]
public static extern UInt32 RegisterHotKey(IntPtr hWnd, UInt32 id, UInt32 fsModifiers, Keys vk);

hWnd:用于接收消息的句柄,一般是this
id:被注册的快捷键的ID,可以设置个ID,但不能重复,推荐用System.Guid.NewGuid()方法获得一个不易被重复的ID.
fsModifiers:快捷键的修饰键(如:Ctrl,Alt或Ctrl+Alt等等),可以使用下面的一些值:

        public const int MOD_ALT = 0x1;        //Alt键,值为1
        public const int MOD_CONTROL = 0x2;    //Ctrl键值为2,如果要用Ctrl+Alt,直接用3就可以了
        public const int MOD_SHIFT = 0x4;      //Shift键值为4

vk:快捷键,如:Keys.A 具体可以查看MSDN的Keys枚举。

===========================================================

接下来还必须要添加一个反注册快捷键的方法:

 [DllImport("user32.dll")]
public static extern UInt32 UnregisterHotKey(IntPtr hWnd, UInt32 id);

hWnd:注册快捷键的窗体句柄。
id:被注册的快捷键的id。(把之前注册快捷键的id放进去就可以了)

刚才用AddMessageFilter方法让消息发给自己的程序,在反注册全部的快捷键后,如果不想让消息再被窗体接收,就该调用 RemoveMessageFilter (IMessageFilter value)

参数: value: IMessageFilter 接口的实现

因为添加消息筛选器会增大系统开销,所以当不再接收消息的时候就要RemoveMessageFilter()。

===========================================================

除此以外,有一个接口:“IMessageFilter”, 我在MSDN中查到:这个接口可以处理消息,这用于是定义消息筛选器的接口。该接口只提供了一个方法PreFilterMessage,作用:在调度消息之前将其筛选出来。

 bool PreFilterMessage (ref Message m)

参数m是程序接收到的消息,消息的Msg 属性如果为0x312 就是快捷键的消息,然后获取消息的WParam 字段,把该字段转换为整型,与设置过的快捷键的id比较,如果有相等,那就可以确定按下了这个快捷键,然后就可以调用相应的方法来实现接下来自己的要做的事。

===========================================================

有了上面的核心解释,就可以了,接下来把完整的代码发出来,以供参考。(源码部分东西是基于网上的摘抄,由于网上的资源比较乱,也不知道原作者了,故在这感谢XXX和XXX)

为方便使用,代码中还添加了一些其他的东西以方便使用(也就是说不是必须的)

 using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace Or
{
    public delegate void HotkeyEventHandler(int HotKeyID);
    public class Hotkey : IMessageFilter       //继承这个接口,才能用AddMessageFilter接收消息
    {
        System.Collections.Hashtable keyIDs = new System.Collections.Hashtable();
        IntPtr hWnd;
        public event HotkeyEventHandler OnHotkey;  //方便对快捷键进行处理
        public const int MOD_ALT = 0x1;
        public const int MOD_CONTROL = 0x2;
        public const int MOD_SHIFT = 0x4;
        public const int MOD_WIN = 0x8;
        public const int WM_HOTKEY = 0x312;    //按下快捷键消息的ID

        [DllImport("user32.dll")]
        public static extern UInt32 RegisterHotKey(IntPtr hWnd, UInt32 id, UInt32 fsModifiers, Keys vk);

        [DllImport("user32.dll")]
        public static extern UInt32 UnregisterHotKey(IntPtr hWnd, UInt32 id);

        [DllImport("kernel32.dll")]
        public static extern UInt32 GlobalAddAtom(String lpString);

        [DllImport("kernel32.dll")]
        public static extern UInt32 GlobalDeleteAtom(UInt32 nAtom);

        public Hotkey(IntPtr hWnd)
        {
            this.hWnd = hWnd;
            Application.AddMessageFilter(this);    //这样this才会收到消息
        }
        public int RegisterHotkey(Keys Key, UInt32 KeyModifiers)
        {
            UInt32 hotkeyid = GlobalAddAtom(System.Guid.NewGuid().ToString());
            RegisterHotKey((IntPtr)hWnd, hotkeyid, KeyModifiers, Key);
            keyIDs.Add(hotkeyid, hotkeyid);
            return (int)hotkeyid;
        }
        public void UnregisterHotkeys()
        {
            Application.RemoveMessageFilter(this);
            foreach (UInt32 key in keyIDs.Values)
            {
                UnregisterHotKey(hWnd, key);
                GlobalDeleteAtom(key);
            }
        }
        ///

        /// 消息过滤器
        /// 

        ///
收到的消息
        /// 如果筛选消息并禁止消息被调度,则为true;如果允许消息继续到达下一个筛选器或控件,则为false。

        public bool PreFilterMessage(ref Message m)
        {
            if (m.Msg == WM_HOTKEY)
            {
                if (OnHotkey != null)
                {
                    foreach (UInt32 key in keyIDs.Values)
                    {
                        if ((UInt32)m.WParam == key)
                        {
                            OnHotkey((int)m.WParam);
                            return true;
                        }
                    }
                }
            }
            return false;
        }
    }
}

使用方法:

1.首先在类级别的位置定义Hotkey的一个方法名:

 Hotkey hk;

2.在快捷键注册方法内实例化

         public void HotkeyReg()
        {
            hk = new Hotkey(this.Handle);
            hk.RegisterHotkey(……); //这里选择自己的快捷键设置,方法返回该快捷键的ID
            hk.OnHotkey += new HotkeyEventHandler(hk_OnHotkey);  //绑定方法
        }
        void hk_OnHotkey(int HotKeyID)
        {
            MessageBox.Show(HotKeyID.ToString());
            //在这里添加if语句,用来处理不同的快捷键ID
        }

这是我第一篇技术博文,有问题请指出,有建议请提出,谢谢。正在学习中。。。
Help each other.

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/gengzhijun/archive/2009/01/31/3855586.aspx

分类: CShap 标签: , ,

C# DllImport的用法

2009年10月23日 没有评论

大家在实际工作学习C#的时候,可能会问:为什么我们要为一些已经存在的功能(比如Windows中的一些功能,C++中已经编写好的一些方法)要重新编写代码,C#有没有方法可以直接都用这些原本已经存在的功能呢?答案是肯定的,大家可以通过C#中的DllImport直接调用这些功能。
DllImport所在的名字空间 using System.Runtime.InteropServices;
MSDN中对DllImportAttribute的解释是这样的:可将该属性应用于方法。DllImportAttribute 属性提供对从非托管 DLL 导出的函数进行调用所必需的信息。作为最低要求,必须提供包含入口点的 DLL 的名称。
DllImport 属性定义如下:

namespace System.Runtime.InteropServices
{
  [AttributeUsage(AttributeTargets.Method)]
  public class DllImportAttribute: System.Attribute
  {
   public DllImportAttribute(string dllName) {...}
   public CallingConvention CallingConvention;
   public CharSet CharSet;
   public string EntryPoint;
   public bool ExactSpelling;
   public bool PreserveSig;
   public bool SetLastError;
   public string Value { get {...} }
  }
} 

  说明:
  1、DllImport只能放置在方法声明上。
  2、DllImport具有单个定位参数:指定包含被导入方法的 dll 名称的 dllName 参数。
  3、DllImport具有五个命名参数:
   a、CallingConvention 参数指示入口点的调用约定。如果未指定 CallingConvention,则使用默认值 CallingConvention.Winapi。
   b、CharSet 参数指示用在入口点中的字符集。如果未指定 CharSet,则使用默认值 CharSet.Auto。
   c、EntryPoint 参数给出 dll 中入口点的名称。如果未指定 EntryPoint,则使用方法本身的名称。
   d、ExactSpelling 参数指示 EntryPoint 是否必须与指示的入口点的拼写完全匹配。如果未指定 ExactSpelling,则使用默认值 false。
   e、PreserveSig 参数指示方法的签名应当被保留还是被转换。当签名被转换时,它被转换为一个具有 HRESULT 返回值和该返回值的一个名为 retval 的附加输出参数的签名。如果未指定 PreserveSig,则使用默认值 true。
   f、SetLastError 参数指示方法是否保留 Win32"上一错误"。如果未指定 SetLastError,则使用默认值 false。
  4、它是一次性属性类。
  5、此外,用 DllImport 属性修饰的方法必须具有 extern 修饰符。

DllImport的用法:

DllImport("MyDllImport.dll")]
private static extern int mySum(int a,int b);

一 在C#程序设计中使用Win32类库
常用对应类型:
1、DWORD 是 4 字节的整数,因此我们可以使用 int 或 uint 作为 C# 对应类型。
2、bool 类型与 BOOL 对应。

示例一:调用 Beep() API 来发出声音
Beep() 是在 kernel32.lib 中定义的,在MSDN 中的定义,Beep具有以下原型:
BOOL Beep(DWORD dwFreq, // 声音频率
DWORD dwDuration // 声音持续时间);
用 C# 编写以下原型:

[DllImport("kernel32.dll")]
public static extern bool Beep(int frequency, int duration);

示例二:枚举类型和常量
MessageBeep() 是在 user32.lib 中定义的,在MSDN 中的定义,MessageBeep具有以下原型:
BOOL MessageBeep(UINT uType // 声音类型
);

用C#编写一下原型:

public enum BeepType
{
  SimpleBeep = -1,
  IconAsterisk = 0x00000040,
  IconExclamation = 0x00000030,
  IconHand = 0x00000010,
  IconQuestion = 0x00000020,
  Ok = 0x00000000,
}

uType 参数实际上接受一组预先定义的常量,对于 uType 参数,使用 enum 类型是合乎情理的。

[DllImport("user32.dll")]
public static extern bool MessageBeep(BeepType beepType);

示例三:处理结构
有时我需要确定我笔记本的电池状况。Win32 为此提供了电源管理函数,搜索 MSDN 可以找到GetSystemPowerStatus() 函数。

BOOL GetSystemPowerStatus(
  LPSYSTEM_POWER_STATUS lpSystemPowerStatus
);

此函数包含指向某个结构的指针,我们尚未对此进行过处理。要处理结构,我们需要用 C# 定义结构。我们从非托管的定义开始:

typedef struct _SYSTEM_POWER_STATUS {
BYTE  ACLineStatus;
BYTE  BatteryFlag;
BYTE  BatteryLifePercent;
BYTE  Reserved1;
DWORD BatteryLifeTime;
DWORD BatteryFullLifeTime;
} SYSTEM_POWER_STATUS, *LPSYSTEM_POWER_STATUS;
   //然后,通过用 C# 类型代替 C 类型来得到 C# 版本。
struct SystemPowerStatus
{
  byte ACLineStatus;
  byte batteryFlag;
  byte batteryLifePercent;
  byte reserved1;
  int batteryLifeTime;
  int batteryFullLifeTime;
}

这样,就可以方便地编写出 C# 原型:

[DllImport("kernel32.dll")]
public static extern bool GetSystemPowerStatus(
  ref SystemPowerStatus systemPowerStatus);
   //在此原型中,我们用“ref”指明将传递结构指针而不是结构值。这是处理通过指针传递的结构的一般方法。
   //此函数运行良好,但是最好将 ACLineStatus 和 batteryFlag 字段定义为 enum:
  enum ACLineStatus: byte
   {
    Offline = 0,
    Online = 1,
    Unknown = 255,
   }
   enum BatteryFlag: byte
   {
    High = 1,
    Low = 2,
    Critical = 4,
    Charging = 8,
    NoSystemBattery = 128,
    Unknown = 255,
   }

请注意,由于结构的字段是一些字节,因此我们使用 byte 作为该 enum 的基本类型

示例四:处理字符串

二 C# 中调用C++代码
int 类型

[DllImport(“MyDLL.dll")]
//返回个int 类型
public static extern int mySum (int a1,int b1);
//DLL中申明
extern “C” __declspec(dllexport) int WINAPI mySum(int a2,int b2)
{
//a2 b2不能改变a1 b1
//a2=..
//b2=...
return a+b;
}

//参数传递int 类型
public static extern int mySum (ref int a1,ref int b1);
//DLL中申明
extern “C” __declspec(dllexport) int WINAPI mySum(int *a2,int *b2)
{
//可以改变 a1, b1
*a2=...
*b2=...
return a+b;
}

DLL 需传入char *类型

[DllImport(“MyDLL.dll")]
//传入值
public static extern int mySum (string astr1,string bstr1);
//DLL中申明
extern “C” __declspec(dllexport) int WINAPI mySum(char * astr2,char * bstr2)
{
//改变astr2 bstr 2 ,astr1 bstr1不会被改变
return a+b;
}

DLL 需传出char *类型

[DllImport(“MyDLL.dll")]
// 传出值
public static extern int mySum (StringBuilder abuf, StringBuilder bbuf );
//DLL中申明
extern “C” __declspec(dllexport) int WINAPI mySum(char * astr,char * bstr)
{
//传出char * 改变astr bstr -->abuf, bbuf可以被改变
return a+b;
}

DLL 回调函数

BOOL EnumWindows(WNDENUMPROC lpEnumFunc, LPARAM lParam)

using System;
using System.Runtime.InteropServices;
public delegate bool CallBack(int hwnd, int lParam); //定义委托函数类型
public class EnumReportApp
{
[DllImport("user32")]
public static extern int EnumWindows(CallBack x, int y);
public static void Main() {
CallBack myCallBack = new CallBack(EnumReportApp.Report); EnumWindows(myCallBack, 0);
}
public static bool Report(int hwnd, int lParam)
{
Console.Write("Window handle is ");
Console.WriteLine(hwnd); return true;
}
}

DLL 传递结构

BOOL PtInRect(const RECT *lprc, POINT pt);

using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Sequential)]
public struct Point {
public int x;
public int y;
}
[StructLayout(LayoutKind.Explicit)]
public struct Rect
{
[FieldOffset(0)] public int left;
[FieldOffset(4)] public int top;
[FieldOffset(8)] public int right;
[FieldOffset(12)] public int bottom;
}
Class XXXX {
[DllImport("User32.dll")]
public static extern bool PtInRect(ref Rect r, Point p);
}

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/jame_peng/archive/2009/07/28/4387906.aspx

分类: CShap 标签: ,

Switch TOR to a new identity

2009年9月23日 没有评论

在程序中使用Tor 的一个关键问题就是如何在程序中强制Tor 使用新的身份(切换代理),如果不能在程序中更换身份那使用Tor 的意义也就不大了。
Tor 默认HTTP代理端口是8118,Socket代理端口是9050,控制端口是9051。我们可以通过向Tor 控制端口发送命令来强制Tor 使用新的身份。
下面有三段代码,分别由shell、php和c#实现切换Tor 使用新的身份。
阅读全文...

分类: CShap 标签: ,