잊지 않겠습니다.

0008. CSWindowsHook

Sample Codes 2010. 1. 5. 16:26
Windows Hooking의 경우에는 Windows message queue에 대한 이해가 좀 필요하다.
Windows는 Windows Message Queue를 통해서 각각의 Message를 전달하고, 그 Message에 따라 각기 다른 Action을 행한다.
WM_PAINT의 경우에는 화면을 그리라는 Message가 되고, WM_MOUSE의 경우에는 Mouse의 움직임에 따라 발생되는 Windows
Message이다.

Hooking은 이런 WIndows Message Queue에 Hook을 걸어서, 원래 처리되어야지 되는 함수가 아닌, 사용자 지정 Method에서
처리하게 하는 방법이다. 이것을 이용하면 Ctrl+Alt+Del의 기능도 막아버릴 수 있으며, 마우스를 움직여서 다른 동작을 하는 것도
막는 것이 가능하다. 또한 Mouse나 Keyboard의 모든 기록들을 저장할 수 있기 때문에 Windows에서 Cracking을 하는 경우에
왕왕 사용되는 방법이다.

먼저, WIN32 함수인 SetWindowsHookEx 함수를 DllImport시켜서 가지고 온다. 필요한 Native method의 선언은 다음과 같다.

internal delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam);

internal class NativeMethods
{
    /// 
    /// Hooking WIN32 API
    /// dwThreadId가 0인 경우에는 전역 hook
    /// 특정 handler안에서 Hooking을 하는 경우에는 Handle 값을 넣어준다.
    /// 
    /// 
    /// Hooking을 한 이후에 받을 method의 주소값 delegate된 method를 넣어줄수 있다.
    /// 
    /// 
    /// 
    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern IntPtr SetWindowsHookEx(HookType hookType, HookProc callback, IntPtr hMod, uint dwThreadId);

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern bool UnhookWindowsHookEx(IntPtr hhk);

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
}

internal static class HookCodes
{
    public const int HC_ACTION = 0;
    public const int HC_GETNEXT = 1;
    public const int HC_SKIP = 2;
    public const int HC_NOREMOVE = 3;
    public const int HC_NOREM = HC_NOREMOVE;
    public const int HC_SYSMODALON = 4;
    public const int HC_SYSMODALOFF = 5;
}

internal enum HookType
{
    WH_KEYBOARD = 2,
    WH_MOUSE = 7,
    WH_KEYBOARD_LL = 13,
    WH_MOUSE_LL = 14
}

[StructLayout(LayoutKind.Sequential)]
internal class POINT
{
    public int x;
    public int y;
}

/// 
/// The MSLLHOOKSTRUCT structure contains information about a low-level keyboard 
/// input event. 
/// 
[StructLayout(LayoutKind.Sequential)]
internal struct MOUSEHOOKSTRUCT
{
    public POINT pt;        // The x and y coordinates in screen coordinates
    public int hwnd;        // Handle to the window that'll receive the mouse message
    public int wHitTestCode;
    public int dwExtraInfo;
}

/// 
/// The MOUSEHOOKSTRUCT structure contains information about a mouse event passed 
/// to a WH_MOUSE hook procedure, MouseProc. 
/// 
[StructLayout(LayoutKind.Sequential)]
internal struct MSLLHOOKSTRUCT
{
    public POINT pt;        // The x and y coordinates in screen coordinates. 
    public int mouseData;   // The mouse wheel and button info.
    public int flags;
    public int time;        // Specifies the time stamp for this message. 
    public IntPtr dwExtraInfo;
}

internal enum MouseMessage
{
    WM_MOUSEMOVE = 0x0200,
    WM_LBUTTONDOWN = 0x0201,
    WM_LBUTTONUP = 0x0202,
    WM_LBUTTONDBLCLK = 0x0203,
    WM_RBUTTONDOWN = 0x0204,
    WM_RBUTTONUP = 0x0205,
    WM_RBUTTONDBLCLK = 0x0206,
    WM_MBUTTONDOWN = 0x0207,
    WM_MBUTTONUP = 0x0208,
    WM_MBUTTONDBLCLK = 0x0209,

    WM_MOUSEWHEEL = 0x020A,
    WM_MOUSEHWHEEL = 0x020E,

    WM_NCMOUSEMOVE = 0x00A0,
    WM_NCLBUTTONDOWN = 0x00A1,
    WM_NCLBUTTONUP = 0x00A2,
    WM_NCLBUTTONDBLCLK = 0x00A3,
    WM_NCRBUTTONDOWN = 0x00A4,
    WM_NCRBUTTONUP = 0x00A5,
    WM_NCRBUTTONDBLCLK = 0x00A6,
    WM_NCMBUTTONDOWN = 0x00A7,
    WM_NCMBUTTONUP = 0x00A8,
    WM_NCMBUTTONDBLCLK = 0x00A9
}

/// 
/// The structure contains information about a low-level keyboard input event. 
/// 
[StructLayout(LayoutKind.Sequential)]
internal struct KBDLLHOOKSTRUCT
{
    public int vkCode;      // Specifies a virtual-key code
    public int scanCode;    // Specifies a hardware scan code for the key
    public int flags;
    public int time;        // Specifies the time stamp for this message
    public int dwExtraInfo;
}

internal enum KeyboardMessage
{
    WM_KEYDOWN = 0x0100,
    WM_KEYUP = 0x0101,
    WM_SYSKEYDOWN = 0x0104,
    WM_SYSKEYUP = 0x0105
}

여기에서 구성된 Hooking method들은 다음과 같다.

private bool SetGlobalLLMouseHook()
{
    // Create an instance of HookProc.
    globalLLMouseHookCallback = new HookProc(this.LowLevelMouseProc);

    hGlobalLLMouseHook = NativeMethods.SetWindowsHookEx(
        HookType.WH_MOUSE_LL,  // Must be LL for the global hook
        globalLLMouseHookCallback,
        // Get the handle of the current module
        Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]),
        // The hook procedure is associated with all existing threads running 
        // in the same desktop as the calling thread.
        0);
    return hGlobalLLMouseHook != IntPtr.Zero;
}

public int LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam)
{
    if(nCode >= 0)
    {
        // Marshal the MSLLHOOKSTRUCT data from the callback lParam
        MSLLHOOKSTRUCT mouseLLHookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));

        // Get the mouse WM from the wParam parameter
        MouseMessage wmMouse = (MouseMessage)wParam;

        // Display the current mouse coordinates and the message
        String log = String.Format("X = {0} Y = {1}  ({2})\r\n", mouseLLHookStruct.pt.x, mouseLLHookStruct.pt.y, wmMouse);
        tbLog.AppendText(log);
    }

    // Pass the hook information to the next hook procedure in chain
    return NativeMethods.CallNextHookEx(hGlobalLLMouseHook, nCode, wParam, lParam);
}
Posted by Y2K
,
별다를 것이 없는 코드.
Visual Studio에서 Generate되는 code만을 간단히 이용하지만, Windows EventLog를 사용하는 법이 나온 부분만 체크해보면 될 것 같다.
또 하나가 있다면, ProjectInstaller 역시 살펴 볼 내용.

Windows Service를 등록하기 위해서는 InstallUtil을 이용해서 Service를 등록시켜야지 되는데 이때 등록할 ServiceName과 Service의
이름을 일치시켜주는 것이 필요하다.


private void InitializeComponent()
{
    ///서비스 등록 Account와 Password, UserName을 명시해준다.
    this.serviceProcessInstaller1 = new System.ServiceProcess.ServiceProcessInstaller();
    this.serviceInstaller1 = new System.ServiceProcess.ServiceInstaller();
    // 
    // serviceProcessInstaller1
    // 
    this.serviceProcessInstaller1.Account = System.ServiceProcess.ServiceAccount.LocalService;
    this.serviceProcessInstaller1.Password = null;
    this.serviceProcessInstaller1.Username = null;
    // 
    // serviceInstaller1
    // 
    ///서비스에 대한 내용을 기술한다. ServiceName의 경우에는 작성한 ServiceName과 반드시 일치해야지 된다.
    this.serviceInstaller1.Description = "All-In-One Code Framework Windows Service example";
    this.serviceInstaller1.DisplayName = "CSWindowsService Sample Service";
    this.serviceInstaller1.ServiceName = "CSWindowsService";
    // 
    // ProjectInstaller
    // 
    this.Installers.AddRange(new System.Configuration.Install.Installer[] {
                                this.serviceProcessInstaller1,
                                this.serviceInstaller1});
}

/// Required method for Designer support - do not modify 
/// the contents of this method with the code editor.
/// Windows EventLog에 대한 초기화를 행한다. 
private System.Diagnostics.EventLog eventLog1;
private void InitializeComponent()
{
    this.eventLog1 = new System.Diagnostics.EventLog();
    ((System.ComponentModel.ISupportInitialize)(this.eventLog1)).BeginInit();
    // 
    // eventLog1
    // 
    this.eventLog1.Log = "Application";
    this.eventLog1.Source = "CSWindowsService";
    // 
    // MyService
    // 
    this.ServiceName = "CSWindowsService";
    ((System.ComponentModel.ISupportInitialize)(this.eventLog1)).EndInit();
}
Posted by Y2K
,
WPF를 이용한 Image animation

System.Windows.Media.Animation.StoryBoard controller를 이용해서 Image Animation을 할 수 있다.
Image Animation 형태는 StoryBoard Controller의 Property들을 변경시키면 가능하다.



int nextImageIndex;
List images = new List();

private void Window_Loaded(object sender, RoutedEventArgs e)
{
    // initialize the images collection
    images.Add(new BitmapImage(new Uri("Images/image1.jpg", UriKind.Relative)));
    images.Add(new BitmapImage(new Uri("Images/image2.jpg", UriKind.Relative)));
    images.Add(new BitmapImage(new Uri("Images/image3.jpg", UriKind.Relative)));
    images.Add(new BitmapImage(new Uri("Images/image4.jpg", UriKind.Relative)));

    nextImageIndex = 2;
}
       
private void VisbleToInvisible_Completed(object sender, EventArgs e)
{
    // change the source of the myImage1 to the next image to be shown 
    // and increase the nextImageIndex
    this.myImage1.Source = images[nextImageIndex++];

    // if the nextImageIndex exceeds the top bound of the ocllection, 
    // get it to 0 so as to show the first image next time
    if (nextImageIndex == images.Count)
    {
        nextImageIndex = 0;
    }

    // get the InvisibleToVisible storyboard and start it
    Storyboard sb = FindResource("InvisibleToVisible") as Storyboard;
    if(sb != null) 
        sb.Begin(this);

}

private void InvisibleToVisible_Completed(object sender, EventArgs e)
{
    // change the source of the myImage2 to the next image to be shown
    // and increase the nextImageIndex
    this.myImage2.Source = images[nextImageIndex++];

    // if the nextImageIndex exceeds the top bound of the ocllection, 
    // get it to 0 so as to show the first image next time
    if (nextImageIndex == images.Count)
    {
        nextImageIndex = 0;
    }

    // get the VisibleToInvisible storyboard and start it
    Storyboard sb = this.FindResource("VisibleToInvisible") as Storyboard;
    if(sb != null) 
        sb.Begin(this);
}   
Posted by Y2K
,