AceHook-2.1

From WowAce Wiki
Jump to: navigation, search


AceHook-2.1 is a Mixin to allow for safe hooking of functions, methods, and scripts.

Example

MyAddon = AceLibrary("AceAddon-2.0"):new("AceHook-2.1") -- hooking mixin

function MyAddon:OnInitialize()
    self:Hook(DEFAULT_CHAT_FRAME, "AddMessage")
    self:Hook(ChatFrame2, "AddMessage")
    self:Hook(ChatFrame3, "AddMessage")
    self:Hook(ChatFrame4, "AddMessage")
    self:Hook(ChatFrame5, "AddMessage")
    self:Hook(ChatFrame6, "AddMessage")
    self:Hook(ChatFrame7, "AddMessage")
    -- those all hook the AddMessage method of the chat frames.
    -- They will be redirected to MyAddon:AddMessage(...)
end

function MyAddon:AddMessage(frame, text, r, g, b, id)
    -- frame is the object that was hooked (one of the ChatFrames)
    -- text, r, g, b, id are the other arguments provided to it.
    local h,m = GetGameTime()
    self.hooks[frame].AddMessage(frame, string.format("[%02d:%02d] %s", h, m, text), r, g, b, id)
    -- self.hooks[object][method] holds the original method.
    -- This should be called every time you deal with hooking, unless you use a secure hook.
    -- be sure to provide all the arguments provided to you as well.
    -- In this case, we pass back the method with modified arguments (adding a timestamp).
    -- Note that if the original AddMessage would be required to return a value you need to do:
    -- return self.hooks[frame].AddMessage(frame, string.format("[%02d:%02d] %s", h, m, text), r, g, b, id)
end

Differences from AceHook-2.0

  • Hooking scripts now work properly for WoW 2.0
  • SecureHook() added
  • :Hook() errors when trying to hook a secure function/method
  • self.hooks.Func.orig() is changed to self.hooks.Func()
  • Much more memory and CPU efficient.
  • :HookReport() now actually works

API Documentation

:Hook("functionName" [, "handlerName" or handler] [, override]) or (object, "methodName" [, "handlerName" or handler] [, override])

Hook a function or method.

Args

"functionName" 
string - global name of the function
object 
table - object which contains the method to hook
"methodName" 
string - name of the method to hook
["handlerName"] 
string - name of the method to handle the hook. If not given, "functionName" or "methodName" is assumed.
[handler] 
function - function to handle the hook.
[override] 
boolean - allow the insecure hook on a secure function.

Remarks

When hooking, you should almost always call the original hook. This is done with

self.hooks["functionName"](...)

or

self.hooks[object]["methodName"](object, ...)

Unless you set override to true, if you try to hook a secure function or method, an error will be raised. Use :SecureHook() instead.

If you know that the function or method you are hooking will not cause tainting issues, then use

:Hook() instead of :SecureHook(), since that can be quite expensive.


Example

function self:UnitName(unit)
    return self.hooks.UnitName(unit)
end
self:Hook("UnitName", true) -- hooking a secure function, thus the true
function self:SomeMethod(object)
    return self.hooks[object].SomeMethod(object)
end
self:Hook(someObject, "SomeMethod")

:SecureHook("functionName" [, "handlerName" or handler]) or (object, "methodName" [, "handlerName" or handler])

Securely hook a function or method, preventing any possible code taint.

Args

"functionName" 
string - global name of the function
object 
table - object which contains the method to hook
"methodName" 
string - name of the method to hook
["handlerName"] 
string - name of the method to handle the hook. If not given, "functionName" or "methodName" is assumed.
[handler] 
function - function to handle the hook.

Remarks

In secure hooking, you do not call the original function, your hook will be called after the original function has executed and your return values will not affect it.

If you know that the function or method you are hooking will not cause tainting issues, then use :Hook() instead of :SecureHook(), since that can be quite expensive.

Example

function self:CastSpellByName(spell, onSelf)
    print("Cast:", spell)
end
self:SecureHook("CastSpellByName")

:Unhook("functionName") or (object, "methodName") or (object, "scriptName")

Safely unhooks from a method, function, or script.

Args

"functionName" 
string - global name of the function
object 
table - object which contains the hooked method/script
"methodName" 
string - name of the hooked method
"scriptName" 
string - name of the script method

Remarks

Unhooking from a function/method which you are not hooked into will cause an error.

Example

self:Unhook("UnitName")
self:Unhook(someObject, "SomeMethod")

:HookScript(object, "scriptName" [, "handlerName" or handler])

Hook a script

Args

object 
table - object which contains the method to hook
"scriptName" 
string - name of the method to hook
["handlerName"] 
string - name of the method to handle the hook. If not given, "scriptName" is assumed.
[handler] 
function - function to handle the hook.

Remarks

When hooking, you should almost always call the original hook. This is done with

self.hooks[object]["scriptName"]()

To unhook, call :Unhook(object, "scriptName"). It intelligently knows the difference between a method and a script.

Example

function self:OnMouseDown(object, mouseButton)
    return self.hooks[object].OnMouseDown(object, mouseButton)
end
self:HookScript(someFrame, "OnMouseDown")

:UnhookAll()

Safely unhooks from all methods, functions, and scripts.

Remarks

This is also called when your addon is put on standby by AceDB-2.0

Example

self:UnhookAll()

:HookReport()

Prints out a report of your current hooks.

Example

self:HookReport()

:IsHooked("functionName") or (object, "methodName")

Returns whether a function, method, or script is hooked

Args

"functionName" 
string - global name of the function
object 
table - object which contains the hooked method/script
"methodName" 
string - name of the hooked method/script

Returns

isHooked, func

isHooked 
boolean - whether a function, method, or script is hooked
func 
string - name of the method
function - function to be called

Example

if self:IsHooked("UnitName") then
    -- do something
end