;---------------------------------------
; 调用Api函数的通用模板 v1.0  By FeiYue
;
; 使用方法:在类中添加各个Api的参数类型模板就可以简单调用了
;
; 参数类型模板规则:
; 模板的函数名区分大小写,简写类型的前面可以加u,后面可以加*
; 返回类型写在最前面接“=”符号,后面的参数类型个数必须准确
; 各参数类型用逗号隔开允许空格,Cdecl调用模式在返回类型前加C
;---------------------------------------

/* 比如调用这个WinAPI函数

int MessageBox(
  HWND    hWnd,
  LPCTSTR lpText,
  LPCTSTR lpCaption,
  UINT    uType
);

*/

; 类的原型对象调用的例子
Api.MessageBox(0, "调用1", "Tip", 0)

; 类的实例对象调用的例子
DLL:=new Api("User32.dll"), DLL.MessageBox(0, "调用2", "Tip", 0)

; 类里面的包装函数调用的例子
Api.msgbox("调用3"), (new Api()).msgbox("调用4")


;======== 下面是通用的类模板代码 ========


Class Api extends ApiBaseClass
{
  ;-- 如果AHK可以不写的DLL,就可以不用New对象而用Api原型对象来调用
  __New(dll:="")
  {
    this.dll:=dll
    if (dll) and !DllCall("GetModuleHandle", "Str",dll)
      DllCall("LoadLibrary", "Str",dll)
  }

  ;-- 为了方便调用,可以添加包装函数
  msgbox(s:="OK", title:="Tip", flag:=0)
  {
    this.MessageBox(0, s, title, flag)
  }
}

Class ApiBaseClass
{
  __Call( func
    ;-- 前面10个参数允许由ByRef参数变量直接返回数值
    , ByRef a1:="" , ByRef a2:=""
    , ByRef a3:="" , ByRef a4:=""
    , ByRef a5:="" , ByRef a6:=""
    , ByRef a7:="" , ByRef a8:=""
    , ByRef a9:="" , ByRef a10:="", arg* )
  {
    ;-- 用于参数这些类型已经足够了,其他char、short只用于数据结构
    ;-- 对于输入的参数都可以不必加u前缀,对于输出的*类型要注意加u
    static type:={ "":"Ptr"
      , i:"Int", i64:"Int64", f:"Float", d:"Double"
      , p:"Ptr", s:"Str", as:"AStr", ws:"WStr" }

    ;-- 在下面可以添加各个Api的参数类型模板,可以简写也可以全写
    ;-- 没有参数的不要写“=”符号只写返回类型,无返回值可不写返回类型
    static typeinfo:={ "":""
      , MessageBox  : "i=p,s,s,i"
      , MessageBoxA : "i=p,as,as,i"
      , MessageBoxW : "i=p,ws,ws,i"
      , "":"" }

    ;-- 将简写的类型转换为完整的AHK类型
    t:=RegExReplace(typeinfo[func], "\s")
    , t:=StrSplit(StrReplace(t, "=", ","), ",")
    , C:=(InStr(t.1,"C") ? "Cdecl ":"")
    , t.1:=RegExReplace(t.1, "i)C(decl)?")
    Loop, % t.Count()
      if (k:=type[Trim(v:=t[A_Index],"uU*")])
        t[A_Index]:=(InStr(v,"u") ? "U":"") k (InStr(v,"*") ? "*":"")
    C.=t.RemoveAt(1), r:=f:=""

    ;-- 调用时不区分大小写,但是模板的函数名区分大小写
    For k,v in typeinfo
      if (k=func) and (f:=(this.dll ? this.dll "\" k : k))
        Break

    ;-- 10个以内的参数类型个数一定要准确
    Switch ( Round(t.Count()) )
    {
      Case 0:  r:=DllCall(f, C)
      Case 1:  r:=DllCall(f, t.1,a1, C)
      Case 2:  r:=DllCall(f, t.1,a1, t.2,a2, C)
      Case 3:  r:=DllCall(f, t.1,a1, t.2,a2, t.3,a3, C)
      Case 4:  r:=DllCall(f, t.1,a1, t.2,a2, t.3,a3, t.4,a4, C)
      Case 5:  r:=DllCall(f, t.1,a1, t.2,a2, t.3,a3, t.4,a4, t.5,a5, C)
      Case 6:  r:=DllCall(f, t.1,a1, t.2,a2, t.3,a3, t.4,a4, t.5,a5, t.6,a6, C)
      Case 7:  r:=DllCall(f, t.1,a1, t.2,a2, t.3,a3, t.4,a4, t.5,a5, t.6,a6, t.7,a7, C)
      Case 8:  r:=DllCall(f, t.1,a1, t.2,a2, t.3,a3, t.4,a4, t.5,a5, t.6,a6, t.7,a7, t.8,a8, C)
      Case 9:  r:=DllCall(f, t.1,a1, t.2,a2, t.3,a3, t.4,a4, t.5,a5, t.6,a6, t.7,a7, t.8,a8, t.9,a9, C)
      Case 10: r:=DllCall(f, t.1,a1, t.2,a2, t.3,a3, t.4,a4, t.5,a5, t.6,a6, t.7,a7, t.8,a8, t.9,a9, t.10,a10, C)

      ;-- 超过10个参数的类型可以只写11个,后面默认用“Ptr”类型
      Default:
      v:=[]
      Loop, % arg.Count()
        v.Push((10+A_Index>t.Count() ? "Ptr":t[10+A_Index]), arg[A_Index])
      v.Push(C)
      r:=DllCall(f, t.1,a1, t.2,a2, t.3,a3, t.4,a4, t.5,a5, t.6,a6, t.7,a7, t.8,a8, t.9,a9, t.10,a10, v*)
    }
    return r
  }
}

 

声明:站内资源为整理优化好的代码上传分享与学习研究,如果是开源代码基本都会标明出处,方便大家扩展学习路径。请不要恶意搬运,破坏站长辛苦整理维护的劳动成果。本站为爱好者分享站点,所有内容不作为商业行为。如若本站上传内容侵犯了原著者的合法权益,请联系我们进行删除下架。