zoukankan      html  css  js  c++  java
  • 巧用Marshal.GetDelegateForFunctionPointerC#如何调用按键精灵插件dll

    原来是为了在游戏外挂中发送键盘鼠标消息,自己写个sendmessage或者是postmessage又比较麻烦。于是google了一下,发现现在很多脚本工具都有这个功能,其中按键精灵的一个叫361度的插件已经有这个的实现,还验证过了。为什么不拿来己用呢?
    首先分析一下按键精灵插件的接口,发现:

    插件的功能函数没有直接暴露出来,而是通过一个GetCommand的函数返回一个函数描述结构。
    接下来看看这个结构:

    上面这个结构我已经是转换成C#的对应结构了,原结构可以查看按键精灵提供的插件C++接口源代码。
    这个结构里面的 handlerFunction 实际上是指向函数的入口点,也就是一个函数指针,每个函数都一样是2个参数:

    typedef int (*QMPLUGIN_HANDLER)(char *lpszParamList, char *lpszRetVal);

    转换为C#中相应的委托为:

    delegate void Invoker(string parameters, StringBuilder returnValue);

    大家注意到,有两个参数,c++原型中都是char*类型,转换为C#的delegate后第一个为string,第二个为StringBuilder。这是因为parameters是in的,dll中不会对这个参数做修改,而returnValue是out的,dll返回时候要把返回值写入这个StringBuilder的缓冲区。

    原本的想法是用C++写一个桥来调用dll,不过在.net 2.0 中,框架直接提供了 Marshal.GetDelegateForFunctionPointer 来转换一个函数指针为一个委托,这就方便多拉。请看下面代码,注意看 BGKM_ExecuteCommand 这个函数里面的东西。
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Runtime.InteropServices;

    namespace WJsHome.Game.Utility
    {
        
    public class QMacro
        {
            [DllImport(
    "BGKM5.dll", EntryPoint = "GetCommand")]
            
    static extern IntPtr BGKM_GetCommand(int commandNum);

            [StructLayout(LayoutKind.Sequential)]
            
    class QMPLUGIN_CMD_INFO
            {
                
    public string commandName;
                
    public string commandDescription;
                
    public IntPtr handlerFunction;
                
    public uint paramNumber;
            }

            
    delegate void Invoker(string parameters, StringBuilder returnValue);

            
    static string BuildParameters(params object[] parameters)
            {
                StringBuilder sb 
    = new StringBuilder();
                
    for (int i = 0; i < parameters.Length; i++)
                {
                    sb.Append(parameters[i].ToString());
                    
    if (i != parameters.Length - 1)
                    {
                        sb.Append(
    ',');
                    }
                }
                
    return sb.ToString();
            }

            
    static void BGKM_ExecuteCommand(int cmdNum, string parameters, StringBuilder retVal)
            {
                IntPtr pCmdInfo 
    = BGKM_GetCommand(cmdNum);
                QMPLUGIN_CMD_INFO cmdInfo 
    = new QMPLUGIN_CMD_INFO();
                Marshal.PtrToStructure(pCmdInfo, cmdInfo);
                Invoker invoker 
    = Marshal.GetDelegateForFunctionPointer(cmdInfo.handlerFunction, typeof(Invoker)) as Invoker;
                invoker(parameters, retVal);
            }

            
    public static void BGKM_KeyClick(IntPtr hWnd, int key)
            {
                BGKM_ExecuteCommand(
    0, BuildParameters(hWnd, key), null);
            }

            
    public static void BGKM_KeyDown(IntPtr hWnd, int key)
            {
                BGKM_ExecuteCommand(
    1, BuildParameters(hWnd, key), null);
            }

            

            
    public static void BGKM_Mouse(IntPtr hWnd, int code, int x, int y)
            {
                BGKM_ExecuteCommand(
    15, BuildParameters(hWnd, code, x, y), null);
            }

            
    public static WinApi.POINT BGKM_ScrToCli(IntPtr hWnd, int x, int y)
            {
                StringBuilder retVal 
    = new StringBuilder();
                BGKM_ExecuteCommand(
    16, BuildParameters(hWnd, x, y), retVal);
                
    string[] tmp = retVal.ToString().Split('|');
                
    return new WinApi.POINT(int.Parse(tmp[0]), int.Parse(tmp[1]));
            }
        }
    }



    好了,方便哇?这样一来,我们可以在.net上面实现动态加载和卸载Win32 dll. 具体思路就是:(还是代码来得方便)
    public delegate int MsgBox(int hwnd,string msg,string cpp,int ok);

    [DllImport(
    "Kernel32")]
    public static extern int GetProcAddress(int handle, String funcname);
    [DllImport(
    "Kernel32")]
    public static extern int LoadLibrary(String funcname);
    [DllImport(
    "Kernel32")]
    public static extern int FreeLibrary(int handle);

    private static Delegate GetAddress(int dllModule, string functionname, Type t)
    {
     
    int addr = GetProcAddress(dllModule, functionname);
     
    if (addr == 0
      
    return null
     
    else 
      
    return Marshal.GetDelegateForFunctionPointer(new IntPtr(addr), t);
    }

    private void button1_Click(object sender, EventArgs e)
    {
     
    int huser32 = 0;
     huser32 
    = LoadLibrary("user32.dll"); 
     MsgBox mymsg 
    = (MsgBox)GetAddress(huser32, "MessageBoxA"typeof(MsgBox));
     mymsg(
    this.Handle.ToInt32(), txtmsg.Text, txttitle.Text , 64);
     FreeLibrary(huser32);
    }
    上面代码是从internet上copy下来的,anyway, enjoy~
  • 相关阅读:
    GitLab 介绍
    git 标签
    git 分支
    git 仓库 撤销提交 git reset and 查看本地历史操作 git reflog
    git 仓库 回退功能 git checkout
    python 并发编程 多进程 练习题
    git 命令 查看历史提交 git log
    git 命令 git diff 查看 Git 区域文件的具体改动
    POJ 2608
    POJ 2610
  • 原文地址:https://www.cnblogs.com/wj/p/1066585.html
Copyright © 2011-2022 走看看