afaik UnmanagedType.FunctionPtr should work fine in this situation no need for the IntPtr crap.
also why bother with a WGUID class...
afaik UnmanagedType.FunctionPtr should work fine in this situation no need for the IntPtr crap.
also why bother with a WGUID class...
Hey, it compiles! Ship it!
well i tried the WGUID thing but it doesn't wort either.
i cant do anything about that, can i?indicates to me that WoW added the First-Object-Offset to a NULL objectlist-pointer and then tried to dereference it.
this is my code. apparently i'm to stupid to find the mistake but maybe someone else can =/Code:using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; namespace Thor { public static class ObjectManager { private static readonly EnumObjectsCallbackDelegate Callback; internal static readonly IntPtr CallbackPtr; private static readonly ClntObjMgrGetObjectPtrDelegate ClntObjMgrGetObjectPtrWoW; private static readonly EnumVisibleObjectsDelegate EnumObjs; private static readonly ClntObjMgrGetActivePlayerDelegate GetActivePlayerDelegate; private static readonly Dictionary<ulong, WoWObject> RealObjects = new Dictionary<ulong, WoWObject>(); private static ulong _frameCounter = 1; internal static ActivePlayer Me { get; private set; } internal static List<WoWObject> ObjectList { get { return RealObjects.Values.Where(o => o.IsValid).ToList(); } } static ObjectManager() { Me = new ActivePlayer(IntPtr.Zero); Callback = EnumObjTest; //EnumObjectsCallbackHandler; CallbackPtr = Marshal.GetFunctionPointerForDelegate(Callback); GetActivePlayerDelegate = Thor_Main.m.RegisterDelegate<ClntObjMgrGetActivePlayerDelegate>((uint)Offsets.ClntObjMgrGetActivePlayer); EnumObjs = Thor_Main.m.RegisterDelegate<EnumVisibleObjectsDelegate>((uint)Offsets.EnumVisibleObjects); ClntObjMgrGetObjectPtrWoW = Thor_Main.m.RegisterDelegate<ClntObjMgrGetObjectPtrDelegate>((uint)Offsets.ClntObjMgrObjectPtr); } public static void Pulse() { if (Me == IntPtr.Zero) { Me = ClntObjMgrGetActivePlayerWow(); ObjectList.Add(Me); } foreach (WoWObject o in RealObjects.Values) { o.UpdateObjectPointer(IntPtr.Zero); } EnumObjs(CallbackPtr, 0); if (_frameCounter++ % 10 == 0) { RemoveInvalidEntries(); } } private static void RemoveInvalidEntries() { IEnumerable<KeyValuePair<ulong, WoWObject>> r = from o in RealObjects where !o.Value.IsValid select o; foreach (var pair in r) { RealObjects.Remove(pair.Key); } } private static int EnumObjTest(WGUID guid, int filter) { return 1; } private static int EnumObjectsCallbackHandler(ulong guid, int filter) { //ulong hGuid = (ulong)highGuid; //ulong temp_hguid = hGuid << 32; //ulong lGuid = (ulong)lowGuid; //ulong guid = temp_hguid | lGuid; IntPtr objPtr = InternalGetObjectByGuid(guid); if (!RealObjects.ContainsKey(guid)) { var tmp = new WoWObject(objPtr); switch (tmp.Type) { case ObjectType.Item: tmp = new Item(objPtr); break; case ObjectType.Container: tmp = new Container(objPtr); break; case ObjectType.Unit: tmp = new Unit(objPtr); break; case ObjectType.Player: tmp = new Player(objPtr); break; case ObjectType.GameObject: tmp = new GameObject(objPtr); break; case ObjectType.Corpse: tmp = new Corpse(objPtr); break; default: return 1; } RealObjects.Add(guid, tmp); } else if (RealObjects[guid] != objPtr) { RealObjects[guid].UpdateObjectPointer(objPtr); } return 1; } internal static WoWObject GetObjectByGuid(ulong guid) { WoWObject ret; RealObjects.TryGetValue(guid, out ret); return ret ?? new WoWObject(IntPtr.Zero); } internal static IntPtr InternalGetObjectByGuid(ulong guid) { return ClntObjMgrGetObjectPtrWoW(guid, -1); } internal static ActivePlayer ClntObjMgrGetActivePlayerWow() { return new ActivePlayer(GetObjectByGuid(GetActivePlayerDelegate())); } [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate ulong ClntObjMgrGetActivePlayerDelegate(); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate IntPtr ClntObjMgrGetObjectPtrDelegate(ulong guid, int filter); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate int EnumObjectsCallbackDelegate(WGUID guid, int filter); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate int EnumVisibleObjectsDelegate(IntPtr callback, int filter); } [StructLayout(LayoutKind.Sequential)] public struct WGUID { public int lowGuid; public int highGuid; public static implicit operator ulong(WGUID obj) { List<byte> tmp = new List<byte>(); tmp.AddRange(BitConverter.GetBytes(obj.lowGuid)); tmp.AddRange(BitConverter.GetBytes(obj.highGuid)); return BitConverter.ToUInt64(tmp.ToArray(), 0); } } }
Are you sure you are calling this from the main-thread? It seems like that's the problem. It uses the TLS, which is different for each thread. This causes it to dereference a pointer with the value 0xAC.
Please verify that WoW freezes completely if you breakpoint the 'Pulse' function.
[16:15:41] Cypher: caus the CPU is a dick
[16:16:07] kynox: CPU is mad
[16:16:15] Cypher: CPU is all like
[16:16:16] Cypher: whatever, i do what i want
You can make sure you are in game when you call EnumVisibleObjects. Robske says it doesn't matter but I've had the same issue as flo. In game doesn't mean in process, it means past the login screen, loading screen etc, you have a character in front of you, trade chat spamming useless dribble and all that jazz.
If you're trying to call this before you login, that could be your problem. If you're not, not sure what the issue is. Nothing is obvious from your code.
well the problem is that i can't debug the .net dll. I can set a breakpoint in the clr loader and it gets hit, bit when i place a breakpoint in the .net code and attach vs to wow the breakpoint does not get hit, but my framecounter gets updated
Then you are doing it wrong, because I can do that. Be sure you are compiling in Debug mode. Try placing this anywhere in your code where it is going to be hit:
A window should pop up asking you to attach a debugger. Select the instance of Visual Studio with your source code.Code:if (!Debugger.IsAttached) { Debugger.Launch(); Debugger.Break(); }
Edit: You don't have to attach a debugger for this. You can pretty much do anything that should stall the thread, and check if WoW freezes. Like Thread.Sleep(5000).
[16:15:41] Cypher: caus the CPU is a dick
[16:16:07] kynox: CPU is mad
[16:16:15] Cypher: CPU is all like
[16:16:16] Cypher: whatever, i do what i want
The Attach call (or whatever - look it up) should cause WoW to 'crash' bringing up that dialog that says "WoW.exe has encountered an error. Would you like to debug the program" or something like that, allowing you to then attach a debugger to WoW (i.e. a separate instance of VS and debug it).Code:System.Diagnostics.Debugger.Attach(); System.Diagnostics.Debugger.Break();
yes it freezes
[16:15:41] Cypher: caus the CPU is a dick
[16:16:07] kynox: CPU is mad
[16:16:15] Cypher: CPU is all like
[16:16:16] Cypher: whatever, i do what i want
i'm using apocs whitemagic
Code:public static int Init(String pwzArgument) { guiThread = new Thread(Init_gui); guiThread.SetApartmentState(ApartmentState.STA); guiThread.Start(); IntPtr endSceneAddr = DirectX.GetEndScenePointer(); m.Detours.CreateAndApply(m.RegisterDelegate<EndSceneDelegate>(endSceneAddr), EndSceneHandler, "EndScene"); return 0; } private static void Init_gui() { window = new Gui(); window.Show(); System.Windows.Threading.Dispatcher.Run(); } private static int EndScene(IntPtr instance) { _frameCounter++; ObjectManager.Pulse(); if (_frameCounter % 30 == 0) { window.Dispatcher.Invoke(new guiPulseDel(window.guiPulse), new object[] { }); } return (int)m.Detours["EndScene"].CallOriginal(instance); }Code:internal static class DirectX { #region Actual Useful Funcs public static IntPtr GetDevicePointer() { return GetDevicePointer(-1); } /// <summary> /// Returns a function pointer for the current DirectX device. /// Pass -1 if you want the actual device pointer. /// </summary> /// <param name="funcIndex">The index to the function you want to retrieve, or -1 for the device pointer itself.</param> /// <returns></returns> public static IntPtr GetDevicePointer(int funcIndex) { // This is required so we can have UnregisterClass properly... unregister... ushort classId = 0; try { // Create a WNDCLASSEXA object to pass to RegisterClassEx var wndClass = new WndClassEx { cbSize = Marshal.SizeOf(typeof (WndClassEx)), style = 0x40, // CS_CLASSDC cbClsExtra = 0, cbWndExtra = 0, hbrBackground = IntPtr.Zero, hCursor = IntPtr.Zero, hIcon = IntPtr.Zero, hIconSm = IntPtr.Zero, lpszClassName = "D3DBlankClass" + Rand.Next(0,10000), lpszMenuName = null, hInstance = IntPtr.Zero, lpfnWndProc = MainWndProc }; // RegisterClassEx returns an ATOM (ushort for .NET) // We use this instead of the 'string' name of the class to avoid silly issues // with the .NET marshaler ****ing things up. classId = RegisterClassEx(ref wndClass); // If it failed, make sure we explain why. (This really shouldn't happen...) if (classId == 0) throw new Win32Exception(Marshal.GetLastWin32Error()); // Create the window, and get the handle. Note; we're passing the ID we retrieved from RegisterClassEx // And passing a bunch of other vals. Leave these as they are. (The IntPtr.Zero is the 'desktop' HWND) IntPtr hwnd = CreateWindowExW(0, classId, "D3DBlankWindow", 0, 0, 0, 1, 1, IntPtr.Zero, 0, 0, 0); // Same as above. Explain why if it fails. if (hwnd == IntPtr.Zero) throw new Win32Exception(Marshal.GetLastWin32Error()); // Grabbed from d3d9.h const uint D3D_SDK_VERSION = 32; // Create the IDirect3D* object. IntPtr direct3D = Direct3DCreate9(D3D_SDK_VERSION); // Make sure it's valid. (Should always be valid....) if (direct3D == IntPtr.Zero) throw new Exception("Failed to create D3D."); // Setup some present params... var d3dpp = new D3DPRESENT_PARAMETERS {Windowed = true, SwapEffect = 1, BackBufferFormat = 0}; IntPtr device; // CreateDevice is a vfunc of IDirect3D. Hence; why this entire thing only works in process! (Unless you // know of some way to hook funcs from out of process...) // It's the 16th vfunc btw. // Check d3d9.h var createDevice = Magic.Instance.RegisterDelegate<IDirect3D9_CreateDevice>(Magic.Instance.GetObjectVtableFunction(direct3D, 16)); // Pass it some vals. You can check d3d9.h for what these actually are.... if (createDevice(direct3D, 0, 1, hwnd, 0x20, ref d3dpp, out device) < 0) throw new Exception("Failed to create device."); // If we passed anything lower than 0, just return the device pointer. Otherwise, // grab the vfunc pointer. (Useful for EndScene/Reset/etc) IntPtr ret = funcIndex < 0 ? device : Magic.Instance.GetObjectVtableFunction(device, (uint)funcIndex); // We now have a valid pointer to the device. We can release the shit we don't need now. :) // Again, the Release() funcs are virtual. Part of the IUnknown interface for COM. // They're the 3rd vfunc. (2nd index) var deviceRelease = Magic.Instance.RegisterDelegate<D3DRelease>(Magic.Instance.GetObjectVtableFunction(device, 2)); var d3dRelease = Magic.Instance.RegisterDelegate<D3DRelease>(Magic.Instance.GetObjectVtableFunction(direct3D, 2)); // And finally, release the device and d3d object. deviceRelease(device); d3dRelease(direct3D); // Destroy the window... DestroyWindow(hwnd); // And we can FINALLY return the pointer to the device or func. return ret; } finally { // Always make sure we unregister the class we created above. Or we'll have some serious issues // when trying to 'reload' the bot and do this process all over again. if (!UnregisterClass(classId, IntPtr.Zero)) throw new Win32Exception(Marshal.GetLastWin32Error()); } } public static IntPtr GetEndScenePointer() { return GetDevicePointer(42); } public static IntPtr GetResetPointer() { return GetDevicePointer(16); } #endregion #region Fields private static readonly Random Rand = new Random(); #endregion #region DllImports [DllImport("user32.dll", SetLastError = true, CharSet=CharSet.Unicode)] static extern bool UnregisterClass(ushort lpClassName, IntPtr hInstance); [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] private static extern IntPtr CreateWindowExW(uint style, ushort lpClassName, string lpWindowName, uint dwStyle, int x, int y, int nWidth, int nHeight, IntPtr hWndParent, uint hMenu, uint hInstance, uint lpParam); [DllImport("user32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.U2)] private static extern ushort RegisterClassEx([In] ref WndClassEx lpwcx); [DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool DestroyWindow(IntPtr hwnd); [UnmanagedFunctionPointer(CallingConvention.StdCall)] private delegate int IDirect3D9_CreateDevice(IntPtr instance, uint adapter, uint deviceType, IntPtr focusWindow, uint behaviorFlags, [In] ref D3DPRESENT_PARAMETERS presentationParameters, [Out] out IntPtr returnedDeviceInterface); [UnmanagedFunctionPointer(CallingConvention.StdCall)] private delegate void D3DRelease(IntPtr instance); [DllImport("d3d9.dll")] private static extern IntPtr Direct3DCreate9(uint sdkVersion); #endregion #region Structs n Shit #region Nested type: D3DPRESENT_PARAMETERS [StructLayout(LayoutKind.Sequential)] private struct D3DPRESENT_PARAMETERS { public uint BackBufferWidth; public uint BackBufferHeight; public uint BackBufferFormat; public uint BackBufferCount; public uint MultiSampleType; public uint MultiSampleQuality; public uint SwapEffect; public IntPtr hDeviceWindow; [MarshalAs(UnmanagedType.Bool)] public bool Windowed; [MarshalAs(UnmanagedType.Bool)] public bool EnableAutoDepthStencil; public uint AutoDepthStencilFormat; public uint Flags; public uint FullScreen_RefreshRateInHz; public uint PresentationInterval; } #endregion #region Nested type: WndClassEx [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] private struct WndClassEx { public int cbSize; public int style; [MarshalAs(UnmanagedType.FunctionPtr)] public WndProc lpfnWndProc; public int cbClsExtra; public int cbWndExtra; public IntPtr hInstance; public IntPtr hIcon; public IntPtr hCursor; public IntPtr hbrBackground; [MarshalAs(UnmanagedType.LPWStr)] public string lpszMenuName; [MarshalAs(UnmanagedType.LPWStr)] public string lpszClassName; public IntPtr hIconSm; } #endregion #region Nested type: WndProc private delegate IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam); #endregion #endregion #region Required to make our custom window work... private static IntPtr MainWndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam) { return (IntPtr)1; } #endregion }
Aha, you are using WPF, are you?
In that case.. Doesn't WPF also use DirectX? Which means that WPF will also have its own EndScene that it's calling. That pretty much means that you might be calling the functions from the WPF EndScene call.
You need to ensure the device is the correct one.
[16:15:41] Cypher: caus the CPU is a dick
[16:16:07] kynox: CPU is mad
[16:16:15] Cypher: CPU is all like
[16:16:16] Cypher: whatever, i do what i want
You calling ObjectManager.Pulse() without checking IsInWorld. That's why it crashing... Check ActivePlayer != 0 before calling it.
Last edited by TOM_RUS; 02-27-2010 at 07:40 AM.