Apologies if this is a stupid question; I'm not overly familiar with Visual Studio and definitely not the new version.
I am trying to hook calls to TextOutA from a Windows application using EasyHook, roughly following this tutorial, in Visual Studio 2019. (I am 100% certain that they are TextOutA; decompiler output indicates as much, and I was able to successfully hook them using C++. Unfortunately C# is far more supported/documented than C++ for EasyHook.)
Per the tutorial I have a console application and a class library as two projects in the same solution. Getting the Visual Studio solution to compile at all was somewhat bumpy -- I had to manually edit the .csproj files to .NET Framework 4.8 (per this question) and it took some tinkering to get it working. But now I am worried that I have tinkered too much.
What happens: The code compiles without errors and warnings, and seemingly runs successfully. However, nothing in the DLL seems to be called; none of its code appears to be executed, a breakpoint in Run() is never hit, and it still compiles if I just get rid of the Run() code entirely.
This is the console app code, so far (filenames redacted; there may well be other issues with this code but I'd have to run it to find out):
    static void Main(string[] args)
        {
            string injectionLibrary = Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "[name of DLL].dll");
            Console.WriteLine(injectionLibrary);
            try
            {
                Int32 processID = 0;
                Process[] process = Process.GetProcessesByName("[process name]");
                Console.Write(process[0]);
                processID = process[0].Id;
                EasyHook.RemoteHooking.Inject(
                        processID,          // ID of process to inject into
                        injectionLibrary,   // 32-bit library to inject (if target is 32-bit)
                        injectionLibrary,   // 64-bit library to inject (if target is 64-bit)
                        null         // the parameters to pass into injected library
                                            // ...
                    );
                Console.WriteLine("Injected, supposedly.");
            }
            catch (Exception e)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine("There was an error while injecting into target: ");
                Console.ResetColor();
                Console.WriteLine(e.ToString());
            }
            Console.ReadKey();
        }
    }
}
And this is the class library:
namespace [DLL name]
{
    public class MySimpleEntryPoint : EasyHook.IEntryPoint
    {
        public MySimpleEntryPoint(EasyHook.RemoteHooking.IContext context)
        {
        }
        public void Run(EasyHook.RemoteHooking.IContext context)
        {
            Console.Write("Test");
            var textOutHook = EasyHook.LocalHook.Create(
                EasyHook.LocalHook.GetProcAddress("Gdi32.dll", "TextOutA"),
                new TextOutDelegate(TextOut_Hook),
                this);
            textOutHook.ThreadACL.SetExclusiveACL(new Int32[] { 0 });
        }
        [UnmanagedFunctionPointer(CallingConvention.StdCall,
                CharSet = CharSet.Unicode,
                SetLastError = true)]
        delegate bool TextOutDelegate(IntPtr orig_handle, int x_value, int y_value, string output_string, int color);
        [DllImport("gdi32.dll", CharSet = CharSet.Unicode, EntryPoint = "TextOutA", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
        static extern bool TextOutA(IntPtr orig_handle, int x_value, int y_value, string lpString, int color);
        bool TextOut_Hook(IntPtr orig_handle, int x_value, int y_value, string output_string, int color)
        {
            // We aren't going to call the original at all... YET
            Console.Write("...intercepted...");
            return false;
        }
    }
}
The console output for the process is as expected, and so is the output of the path: C:\Users[my username]\source\repos[name of project]\build\net48\ [name of DLL].dll -- which is indeed where the dll is output to. But, as above, nothing in Run() seems to actually be called, TextOutA certainly isn't being suppressed, etc.
What I have tried:
- Adding both the .dll and the class library project (separately) as references to the console app
- Setting both the .dll and the executable to output to the same folder
- Tweaking the line of code that supposedly gets the path
- Comparing this code to basically any comparable EasyHook projects I can find, nothing seems obviously amiss
- Calling GetProcAddress from within the console app and not the hook; it works as expected, so the problem doesn't seem to be that
Any help would be much appreciated.
 
                        
Answer as per my comment.
There are two things happening in your example:
The managed EasyHook helper library
EasyLoadruns yourIEntryPoint.Runmethod within a new thread and waits for it to exit. When the method exits the assembly is unloaded etc.Therefore you should add a while loop at the end of your
Runmethod to prevent it exiting until you are finished with your hooks.