Problems detouring an internal class method

Started by Robostove, December 04, 2016, 09:04:00 PM

Previous topic - Next topic

Robostove

Here's my detour. The reflections are being found, selectedObjects is correctly being set to a Verse.WindowStack.
I'm getting a crash when objList tries to AddRange selectedObjects due to an access violation. This seems odd to me as before that line I have already interacted with both objList and selectedObjects. I guess the actual contents of selectedObjects are the problem? Is it actually possible to interact with an internal class or is this fruitless? Thanks.


    static class Detours_InspectGizmoGrid
    {
        //Reflect MainTabWindow_Inspect class (it is internal static)
        static Type _InspectGizmoGrid = Type.GetType("RimWorld.InspectGizmoGrid, Assembly-CSharp, Version=0.15.6089.4186, Culture=neutral, PublicKeyToken=null");//version determined using .NET IL Dissasembler

        //Reflect required fields from reflected class
        static List<object> objList =
            (List<object>)_InspectGizmoGrid
                .GetField("objList", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null);

        static List<Gizmo> gizmoList =
            (List<Gizmo>)_InspectGizmoGrid
                .GetField("gizmoList", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null);


        private static void DrawInspectGizmoGridFor(this MainTabWindow_Inspect _this, IEnumerable<object> selectedObjects)
        {

            if (_InspectGizmoGrid == null)
            {
                Log.Error("Reflected InspectGizmoGrid not found.");
                return;
            }
            if (objList == null)
            {
                Log.Error("Reflected objList not found.");
                return;
            }
            if (gizmoList == null)
            {
                Log.Error("Reflected gizmoList not found.");
                return;
            }

            try
            {
                Log.Message("Enter Draw Inspect");
                Log.Message($"{selectedObjects.ToString()}");
                if (selectedObjects == null)
                {
                    Log.Message("selectedObjects is null");
                }
                Log.Message("parameter accessed!");
                objList.Clear();
                Log.Message("objList cleared");
                objList.AddRange(selectedObjects); //CRASH here. Access violation due to read/write without permission.
                Log.Message("objList added selectedObjects");
                gizmoList.Clear();
                Log.Message("Start selectable");
                //...


Injecting this detour with RawCode's TryDetourFromTo:

    [StaticConstructorOnStartup]
    internal static class DetourInjector
    {
        static DetourInjector()
        {
            LongEventHandler.QueueLongEvent(Inject, "LibraryStartup", false, null);
        }

        public static void Inject()
        {
            if (InjectDetours()) Log.Message("Detour Core injected.");
            else Log.Error("Detour Core failed to get injected.");
        }

        public static bool InjectDetours()
        {
            if (!Detours.TryDetourFromTo(Detours_InspectGizmoGrid._InspectGizmoGrid.GetMethod("DrawInspectGizmoGridFor", BindingFlags.Static | BindingFlags.Public),
                typeof(Detours_InspectGizmoGrid).GetMethod("DrawInspectGizmoGridFor", BindingFlags.Static | BindingFlags.NonPublic)))
                return false;
           
            return true;
        }
    }


1000101

Instead of using AddRange(), try looping through the enumerable to see if a specific element is causing the issue.
(2*b)||!(2*b) - That is the question.
There are 10 kinds of people in this world - those that understand binary and those that don't.

Powered By

Robostove

Well turns out there's nothing to enumerate through, selectedObjects.Count is 0. I think I'm not getting the correct parameter. selectedObjects should be a List<IEnumerable>, not a WindowStack. Trying to call AddRange on a WindowStack must be giving the access violation. This is my first time detouring a method with parameters so I suppose I need to do something special to deal with that.

I'll figure it out with a non-internal class first  ;).

1000101

There is nothing special about detouring a method with parameters, your parameter list just has to match the original method.  (Aside from the addition of the "this" parameter at the start of the parameter list, which is actually a hidden first parameter for instance methods).
(2*b)||!(2*b) - That is the question.
There are 10 kinds of people in this world - those that understand binary and those that don't.

Powered By

Robostove

Thanks 0x45, your comment on the extension method parameter made me think "hey wait, I'm detouring a static class why do I have that parameter?". I forgot that originally I was detouring MainTabWindow_Inspect, and then changed it to InspectGizmoGrid (a static class). Aaaand I left that parameter in the declaration.  :P What I thought was a complicated error due to detouring an internal was just a stupid oversight on my part. It works fine now.

RawCode

just read any article about "x86 call opcode"

1000101

#6
An article on platform calling conventions and specific compiler implementations would be more useful.  I don't disagree that every programmer should have a good working knowledge of assembly (not limited to specific opcodes) for the architecture they are working on.  But both this and RawCode's post are rather offtopic.
(2*b)||!(2*b) - That is the question.
There are 10 kinds of people in this world - those that understand binary and those that don't.

Powered By