So I have this very basic cs file which is a .dll file.
And I am using Process Hacker to inject in manually to my NotePad process..
At this point it should execute it and run the MessageBox correct?
(Correct me if im wrong on that one)
At first I thought it was something wrong with my injector but it seems to be the dll. (Feel free to check through the Injector down below)
(Its my first ever attempt on creating a dll file)
Do I need to make the Dll hook somehow and or is it something really simple im missing?
The DLL.
using System;
using System.Windows.Forms;
namespace SomeName
{
public class Class1
{
public static void Main()
{
MessageBox.Show("Lets try this");
}
}
}
The Injector
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace FormDLLInjection
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
[DllImport("kernel32")]
public static extern IntPtr CreateRemoteThread(
IntPtr hProcess,
IntPtr lpThreadAttributes,
uint dwStackSize,
UIntPtr lpStartAddress, // raw Pointer into remote process
IntPtr lpParameter,
uint dwCreationFlags,
out IntPtr lpThreadId
);
[DllImport("kernel32.dll")]
public static extern IntPtr OpenProcess(
UInt32 dwDesiredAccess,
Int32 bInheritHandle,
Int32 dwProcessId
);
[DllImport("kernel32.dll")]
public static extern Int32 CloseHandle(
IntPtr hObject
);
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
static extern bool VirtualFreeEx(
IntPtr hProcess,
IntPtr lpAddress,
UIntPtr dwSize,
uint dwFreeType
);
[DllImport("kernel32.dll", CharSet = CharSet.Ansi, ExactSpelling = true)]
public static extern UIntPtr GetProcAddress(
IntPtr hModule,
string procName
);
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
static extern IntPtr VirtualAllocEx(
IntPtr hProcess,
IntPtr lpAddress,
uint dwSize,
uint flAllocationType,
uint flProtect
);
[DllImport("kernel32.dll")]
static extern bool WriteProcessMemory(
IntPtr hProcess,
IntPtr lpBaseAddress,
string lpBuffer,
UIntPtr nSize,
out IntPtr lpNumberOfBytesWritten
);
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr GetModuleHandle(
string lpModuleName
);
[DllImport("kernel32", SetLastError = true, ExactSpelling = true)]
internal static extern Int32 WaitForSingleObject(
IntPtr handle,
Int32 milliseconds
);
public Int32 GetProcessId(String proc)
{
Process[] ProcList;
ProcList = Process.GetProcessesByName(proc);
return ProcList[0].Id;
}
public void InjectDLL(IntPtr hProcess, String strDLLName)
{
IntPtr bytesout;
// Length of string containing the DLL file name +1 byte padding
Int32 LenWrite = strDLLName.Length + 1;
// Allocate memory within the virtual address space of the target process
IntPtr AllocMem = (IntPtr)VirtualAllocEx(hProcess, (IntPtr)null, (uint)LenWrite, 0x1000, 0x40); //allocation pour WriteProcessMemory
// Write DLL file name to allocated memory in target process
WriteProcessMemory(hProcess, AllocMem, strDLLName, (UIntPtr)LenWrite, out bytesout);
// Function pointer "Injector"
UIntPtr Injector = (UIntPtr)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
if (Injector == null)
{
MessageBox.Show(" Injector Error! \n ");
// return failed
return;
}
// Create thread in target process, and store handle in hThread
IntPtr hThread = (IntPtr)CreateRemoteThread(hProcess, (IntPtr)null, 0, Injector, AllocMem, 0, out bytesout);
// Make sure thread handle is valid
if (hThread == null)
{
//incorrect thread handle ... return failed
MessageBox.Show(" hThread [ 1 ] Error! \n ");
return;
}
// Time-out is 10 seconds...
int Result = WaitForSingleObject(hThread, 10 * 1000);
// Check whether thread timed out...
if (Result == 0x00000080L || Result == 0x00000102L || Result == 0xFFFFFFFF)
{
/* Thread timed out... */
MessageBox.Show(" hThread [ 2 ] Error! \n ");
// Make sure thread handle is valid before closing... prevents crashes.
if (hThread != null)
{
//Close thread in target process
CloseHandle(hThread);
}
return;
}
// Sleep thread for 1 second
Thread.Sleep(1000);
// Clear up allocated space ( Allocmem )
VirtualFreeEx(hProcess, AllocMem, (UIntPtr)0, 0x8000);
// Make sure thread handle is valid before closing... prevents crashes.
if (hThread != null)
{
//Close thread in target process
CloseHandle(hThread);
}
// return succeeded
return;
}
private void injectBtn_Click(object sender, EventArgs e)
{
String strDLLName = #"DllPath"; // here you put the dll you want, only the path.
String strProcessName = "notepad"; //here you will put the process name without ".exe"
Int32 ProcID = GetProcessId(strProcessName);
if (ProcID >= 0)
{
IntPtr hProcess = (IntPtr)OpenProcess(0x1F0FFF, 1, ProcID);
if (hProcess == null)
{
MessageBox.Show("OpenProcess() Failed!");
return;
}
else
InjectDLL(hProcess, strDLLName);
}
}
}
}
Why isnt my class file executing when launching it in memory?
Sadly, you can't just inject .NET assemblies into a native process that hasn't loaded the CLR in the first place. .NET won't magically do that when you attempt to load a managed DLL from a native process. The only exception to the latter is if your managed code is being exposed as COM objects.
Now your code might actually be causing Notepad to attempt to load your .dll, but due to the absence of DllMain (Windows is expecting it to be a native DLL at this point) will fail.
As a follow-up to cdkMoose's, comment, even if you called it DllMain, by default Main or DllMain are not present in the managed assemblies EXPORTS table because there isn't one. There are additional steps for manually exposing a managed method to appear as an EXPORT entry that native processes will recognise.
Is it all moot?
Let's assume that NotePad had prepared a CLR environment prior in the exact same way that SQL Server does. It would look something like this:
e.g.
HRESULT hr;
ICLRMetaHost *pMetaHost = NULL;
ICLRRuntimeInfo *pRuntimeInfo = NULL;
ICLRRuntimeHost *pClrRuntimeHost = NULL;
// build runtime
hr = CLRCreateInstance(CLSID_CLRMetaHost, IID_PPV_ARGS(&pMetaHost));
hr = pMetaHost->GetRuntime(L"v4.0.30319", IID_PPV_ARGS(&pRuntimeInfo));
hr = pRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost,
IID_PPV_ARGS(&pClrRuntimeHost));
// start runtime
hr = pClrRuntimeHost->Start();
Then in that case NotePad or SQL would not use LoadLibraryA for your assembly but rather:
eg.
// execute managed assembly
DWORD pReturnValue;
hr = pClrRuntimeHost->ExecuteInDefaultAppDomain(
L"T:\\FrameworkInjection\\_build\\debug\\anycpu\\InjectExample.exe",
L"InjectExample.Program",
L"EntryPoint",
L"hello .net runtime",
&pReturnValue);
...assuming your .NET assembly is exposing a static int EntryPoint(String pwzArgument).
Conclusion
So the concern over:
whether it should be called Main or DllMain
building and exposing an EXPORT entry in managed code
...we need not be concerned with because:
The native process must be preparing a CLR environment first
A native process hosting the CLR won't care what you call your static method
CLR does not require an EXPORTS table
Native code uses the native CLR APIs to load and run an assembly (not a direct call to LoadLibrary)
The native process must load the CLR first before you can inject your code.
Related
A process maybe loaded many dlls, is there a way to get the module handle of some dll the code is running inside (not the module handle of current process).
It is easier in C++
// a.dll
HMODULE GetCurrentModule() {
HMODULE hModule = NULL;
GetModuleHandleEx(
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
(LPCTSTR)GetCurrentModule,
&hModule);
return hModule;
}
// FreeLibrary in other place
In this way, I can get the module handle of a.dll. I tried to migrate this method to C#,
public const int GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS = 0x00000004;
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public extern static Int32 GetModuleHandleExW(UInt32 dwFlags, IntPtr lpModuleName, out IntPtr phModule);
...
// my.dll (managed dll)
private delegate IntPtr MyFuncDelegate();
private static IntPtr GetCurrentModule()
{
IntPtr hModule = IntPtr.Zero;
MyFuncDelegate f = GetCurrentModule;
IntPtr thisFuncAddress = Marshal.GetFunctionPointerForDelegate(f);
GetModuleHandleExW(
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
thisFuncAddress,
out hModule);
// int errorCode = Marshal.GetLastWin32Error(); // 126
return hModule;
}
But everytime GetCurrentModule was called, it always returned 0x00000000. Where did I make a bug?
I'm to trying to call FreeLibraryAndExitThread externally in another process (using CreateRemoteThread) so that I can unload a module I loaded in externally through LoadLibrary.
I understand that whilst CreateRemoteThread takes 1 parameter, you can provide it with a struct of multiple arguments if you need more than one.
If have tried the following which did not unload the module. In fact it seemed to do nothing.
Note I have removed all error checking to keep this post simple and short
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern IntPtr GetModuleHandle(string moduleName);
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern IntPtr GetProcAddress(IntPtr moduleHandle, string procName);
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern IntPtr VirtualAllocEx(IntPtr processHandle, IntPtr baseAddress, int size, int allocationType, int protection);
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern bool WriteProcessMemory(IntPtr processHandle, IntPtr baseAddress, byte[] buffer, int size, int bytesWritten);
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern IntPtr CreateRemoteThread(IntPtr processHandle, IntPtr threadAttributes, int stackSize, IntPtr startAddress, IntPtr parameter, int creationFlags, int threadId);
private struct FreeLibraryAndExitThreadParameters
{
internal IntPtr ModuleAddress;
internal int ExitCode;
}
var process = Process.GetProcessesByName("notepad")[0];
var freeLibraryAndExitThreadAddress = GetProcAddress(GetModuleHandle("kernel32.dll"), "FreeLibraryAndExitThread");
// Get an instance of the module - dllName is the name of the module I am trying to unload
var module = process.Modules.Cast<ProcessModule>().SingleOrDefault(m => string.Equals(m.ModuleName, dllName, StringComparison.OrdinalIgnoreCase));
var freeLibraryAndExitThreadParameters = new FreeLibraryAndExitThreadParameters { ModuleAddress = module.BaseAddress, ExitCode = 0 };
// This code turns the struct into a byte array
var structureSize = Marshal.SizeOf(freeLibraryAndExitThreadParameters);
var structureBytes = new byte[structureSize];
var buffer = Marshal.AllocHGlobal(structureSize);
Marshal.StructureToPtr(freeLibraryAndExitThreadParameters, buffer, true);
Marshal.Copy(buffer, structureBytes, 0, structureSize);
Marshal.FreeHGlobal(buffer);
// Allocate memory in the remote process with commit and reserve allocation type and PageExecuteReadWrite permissions
var remoteAddress = VirtualAllocEx(process.Handle, IntPtr.Zero, structureSize, 0x01000 | 0x02000, 0x040);
// Write the structure into the remote process
WriteProcessMemory(process.Handle, remoteAddress, buffer, structureSize, 0);
// Finally call CreateRemoteThread to execute the function in the remote process
CreateRemoteThread(process.Handle, IntPtr.Zero, 0, freeLibraryAndExitThreadAddress, remoteAddress, 0, 0);
None of the pinvoke calls are actually failing and I can see that the bytes are being written into memory but nothing seems to happen after the remote thread is created - In my actual code I call WaitForSingleObject and the thread finishes its task also with no problem.
Can someone point out what I'm doing wrong and how I can fix this problem so that I can externally call FreeLibraryAndExitThread in a remote process?
It may be worth mentioning that I can use FreeLibrary with this method - it works fine(removing the struct as it only takes 1 parameter) but I specifically need to use FreeLibraryAndExitThread for the module I need to unload which is why I am not using the simpler FreeLibrary.
formally this is simply, all what we need
CreateRemoteThread(hProcess, 0, 0, (PTHREAD_START_ROUTINE)FreeLibraryAndExitThread, hmod, 0, 0)
where hmod is address of module in remote process. address of FreeLibraryAndExitThread can be take from current process kernel32!FreeLibraryAndExitThread - until kernel32.dll is loaded at the same base address in all processes.
that
DECLSPEC_NORETURN
VOID
WINAPI
FreeLibraryAndExitThread(
_In_ HMODULE hLibModule,
_In_ DWORD dwExitCode
);
take 2 parameters in concrete case no problem. as result of call - CreateRemoteThread(hProcess, 0, 0, (PTHREAD_START_ROUTINE)FreeLibraryAndExitThread, hmod, 0, 0) the FreeLibraryAndExitThread will be called via stdcall (WINAPI) calling convention with single parameter - hmod. the second parameter dwExitCode will be undefined in this case, but it not play any role - any return code of thread is ok. system not interpret this value. and because this concrete api never return - different in parameter count also not play role.
another question - for what, which sense unload module in remote process. and if module really will be unloaded (the FreeLibrary call only decrement module load count, so module not always will be unloaded during this call) and after this some code in remote process call code of unloading module - think not need explain what is be in this case
I have several DLL files that are on my hard disk. A process on my server contains important file data that I want to log by allocating virtual memory inside the process. I don't have the source code of that process, so I need to reside to more extreem measures. I want it to start the DLL main function. The allocation of memory externally needs to be written in C# due to the fact I want to use it with WPF.
How can you excute your own source code in another process with C#?
In order to execute your own source code inside a process you need to virtually allocate memory for the process and write the path of your DLL inside that memory address you allocated. You will use that DLL path to catapult your dll inside the process using the exported function in kernel32.dll LoadLibraryW.
Each process on the windows platform has a specified memory size dedicated to that process. One of the reasons is for security, a process can’t read or write data to other processes. So in order to be able to write/inject your DLL you need to open a HANDLE. You can do this if you import the OpenProcess function from the kernel32.dll. What this briefly means is that you are using the windows api. Here is how you import the kernel32 DLL in C#
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr OpenProcess(
uint dwDesiredAccess,
int bInheritHandle,
uint dwProcessId
);
You can find the full documentation of the windows api in the holy bible
Now, you want to allocate memory to the process that you got a handle from by using the OpenProcess function. Use the VirtualAllocEx function, lets consult the MSDN
How hath thou allocated thou memory?
LPVOID WINAPI VirtualAllocEx(
_In_ HANDLE hProcess,
_In_opt_ LPVOID lpAddress,
_In_ SIZE_T dwSize,
_In_ DWORD flAllocationType,
_In_ DWORD flProtect
);
As we can see it takes 5 parameters. The HANDLE object that you collected earlier. An optional parameter that we won’t use. The size of your DLL that you can get if you convert your DLL into an array of bytes. The type of memory allocation, we want to both reserve and commit allocation so use (0x1000 | 0x2000) and last the protection for the allocated memory that we will put on write 0x40.
STEP 1 Allocate memory ✓
STEP 2 Write DLL path
STEP 3 use LoadLibraryW
The second step involves using WriteProcessMemory to simply write the dll path in memory. Convert String to array of bytes
byte[] bytes = Encoding.ASCII.GetBytes(DllPath);
Write that array of bytes on the memory you allocated with the windows api function WriteProcessMemory like so.
WriteProcessMemory(processHandle, allocatedMemory, bytes, (uint)bytes.Length, 0)
STEP 1 Allocate memory ✓
STEP 2 Write DLL path ✓
STEP 3 use LoadLibraryW
This will be a bit tricky to explain if you have no clue on what exported functions are so ill try to give you an abstract understanding.
When creating an application you need to import DLLs that windows provided in order to use some functionalities. For example, you want to send a HTTP request in your application. Even without you knowing you need to load windows ws2.dll (windows socket) library. The windows OS provided a handy function that will literally load a library called LoadLibraryW. Where can I find this fantastic function? Well no worries child, the kernel32.dll got you covered. All you need to do is find a pointer to the LoadLibraryW function. Again, show faith in the MSDN and it shall reward you.
FARPROC WINAPI GetProcAddress(
_In_ HMODULE hModule,
_In_ LPCSTR lpProcName
);
HMODULE WINAPI GetModuleHandle(
_In_opt_ LPCTSTR lpModuleName
);
You can read the documentation for more information. Simply put this will find your LoadLibraryW function inside kernel32.dll since it is an exported function.
IntPtr lpLLAddress = GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryW");
STEP 1 Allocate memory ✓
STEP 2 Write DLL path ✓
STEP 3 use LoadLibraryW ✓
Start a remotethread inside your process that will simply execute your loadlibrary code
CreateRemoteThread(hndProc, (IntPtr)null, (IntPtr)null, lpLLAddress, lpAddress, 0, (IntPtr)null)
After that simply close the handle to the process and your dll should be ‘injected’ inside the process. At any rate if you still haven't figured it out or simply want a class that does it for you here is some source code
DLLinjector
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
namespace dllInjectExample
{
public enum DllInjectionResult
{
DllNotFound,
GameProcessNotFound,
InjectionFailed,
Success
}
public static class DllInjector
{
static readonly IntPtr INTPTR_ZERO = (IntPtr)0;
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr OpenProcess(uint dwDesiredAccess, int bInheritHandle, uint dwProcessId);
[DllImport("kernel32.dll", SetLastError = true)]
static extern int CloseHandle(IntPtr hObject);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, IntPtr dwSize, uint flAllocationType, uint flProtect);
[DllImport("kernel32.dll", SetLastError = true)]
static extern int WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] buffer, uint size, int lpNumberOfBytesWritten);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttribute, IntPtr dwStackSize, IntPtr lpStartAddress,
IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);
public static DllInjectionResult Inject(string sProcName, string sDllPath)
{
if (!File.Exists(sDllPath))
{
return DllInjectionResult.DllNotFound;
}
uint _procId = 0;
Process[] _procs = Process.GetProcesses();
for (int i = 0; i < _procs.Length; i++)
{
if (_procs[i].ProcessName == sProcName)
{
_procId = (uint)_procs[i].Id;
break;
}
}
if (_procId == 0)
{
return DllInjectionResult.GameProcessNotFound;
}
if (!bInject(_procId, sDllPath))
{
return DllInjectionResult.InjectionFailed;
}
return DllInjectionResult.Success;
}
private static bool bInject(uint pToBeInjected, string sDllPath)
{
IntPtr hndProc = OpenProcess((0x2 | 0x8 | 0x10 | 0x20 | 0x400), 1, pToBeInjected);
if (hndProc == INTPTR_ZERO)
{
return false;
}
IntPtr lpAddress = VirtualAllocEx(hndProc, (IntPtr)null, (IntPtr)sDllPath.Length, (0x1000 | 0x2000), 0X40);
if (lpAddress == INTPTR_ZERO)
{
return false;
}
byte[] bytes = Encoding.ASCII.GetBytes(sDllPath);
if (WriteProcessMemory(hndProc, lpAddress, bytes, (uint)bytes.Length, 0) == 0)
{
return false;
}
IntPtr lpLLAddress = GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryW");
if (lpLLAddress == INTPTR_ZERO)
{
return false;
}
if (CreateRemoteThread(hndProc, (IntPtr)null, INTPTR_ZERO, lpLLAddress, lpAddress, 0, (IntPtr)null) == INTPTR_ZERO)
{
return false;
}
CloseHandle(hndProc);
return true;
}
}
}
Example injecting into csgo since I have no other idea why you would want to inject a dll?
if (Process.GetProcessesByName("csgo").Count() == 0)
{
Process Proc = new Process();
ProcessStartInfo startInfo = new ProcessStartInfo(#"D:\Application\Steam\Steam.exe");
Proc.StartInfo = startInfo;
Proc.StartInfo.Arguments = "-applaunch 730";
Proc.StartInfo.UseShellExecute = false;
Proc.StartInfo.CreateNoWindow = false;
Proc.Start();
Thread.Sleep(15000);
}
while (Process.GetProcessesByName("csgo").Count() == 0)
{
}
var something = DllInjector.Inject("csgo", #"C:\Visual Studio 2015\Projects\XGame\Debug\XGamedll.dll");
I'm looking for a way to tell whether or not an EXE file contains an application icon. From the answer here, I tried this:
bool hasIcon = Icon.ExtractAssociatedIcon(exe) != null;
But this seems to work even if the EXE has no icon. Is there a way to detect this in .NET?
edit: I'm OK with solutions involving P/Invoke.
You can get the IDI_APPLICATION icon through SystemIcons.Application property from SystemIcons class
if (Icon.ExtractAssociatedIcon(exe).Equals(SystemIcons.Application))
{
...
}
See MSDN for more details.
Try this. Define your pinvoke like this:
[DllImport("user32.dll")]
internal static extern IntPtr LoadImage(IntPtr hInst, IntPtr name, uint type, int cxDesired, int cyDesired, uint fuLoad);
[DllImport("kernel32.dll")]
static extern bool EnumResourceNames(IntPtr hModule, int dwID, EnumResNameProcDelegate lpEnumFunc, IntPtr lParam);
delegate bool EnumResNameProcDelegate(IntPtr hModule, IntPtr lpszType, IntPtr lpszName, IntPtr lParam);
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern IntPtr LoadLibraryEx(string name, IntPtr handle, uint dwFlags);
private const int LOAD_LIBRARY_AS_DATAFILE = 0x00000002;
private const int LOAD_LIBRARY_AS_IMAGE_RESOURCE = 0x00000020;
private const int IMAGE_ICON = 1;
private const int RT_GROUP_ICON = 14;
Then you can write a function like this:
static bool HasIcon(string path)
{
// This loads the exe into the process address space, which is necessary
// for LoadImage / LoadIcon to work note, that LOAD_LIBRARY_AS_DATAFILE
// allows loading a 32-bit image into 64-bit process which is otherwise impossible
IntPtr moduleHandle = LoadLibraryEx(path, IntPtr.Zero, LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE);
if (moduleHandle == IntPtr.Zero)
{
throw new ApplicationException("Cannot load executable");
}
IntPtr index = IntPtr.Zero;
bool hasIndex = false;
bool enumerated = EnumResourceNames(moduleHandle, RT_GROUP_ICON, (module, type, name, param) =>
{
index = name;
hasIndex = true;
// Only load first icon and bail out
return false;
}, IntPtr.Zero);
if (!enumerated || !hasIndex)
{
return false;
}
// Strictly speaking you do not need this you can return true now
// This is to demonstrate how to access the icon that was found on
// the previous step
IntPtr result = LoadImage(moduleHandle, index, IMAGE_ICON, 0, 0, 0);
if (result == IntPtr.Zero)
{
return false;
}
return true;
}
It has added bonus that if you want to, after LoadImage you can load the icon with
Icon icon = Icon.FromHandle(result);
and do whatever you want with that.
Important note: I have not done any clean up in the function, so you cannot use it as is, you'll leak handles/memory. Proper clean up is left as an exercise for the reader. Read the description of every of the winapi function used in MSDN and call corresponding clean up functions as needed.
An alternate way using shell32 api can be found here, although I don't know if it has the same problem you encountered.
Also, old, but still very relevant article: https://msdn.microsoft.com/en-us/library/ms997538.aspx
I am trying to set windows hooks in my program to an external EXE. This will be used to monitor resizing/minimizing of the window, so I can resize my program similarly, docking to the window.
How do I get around error codes 1428 and 126 below?
When calling SetWindowsHookEx with a null hMod, I was getting this error 1428. I get the same error if passing the current module (instead of IntPtr.Zero), which it seems to get correctly, as so:
IntPtr module = PInvoke.GetModuleHandle(null);
[...]
SetWindowsHookEx(...,...,module,...);
int error = PInvoke.GetLastError();
1428 = Cannot set nonlocal hook without a module handle
I also tried to grab the external program I'm hooking as a module using GetModuleHandle:
IntPtr module = PInvoke.GetModuleHandle("communicator.exe");
int error = PInvoke.GetLastError();
But error is then set to:
126 = The specified module could not be found.
I am using the following PInvoke statements:
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr SetWindowsHookEx(HookType hookType, HookProc lpfn, IntPtr hMod, uint dwThreadId);
This is the procedure that is having the issue:
public void Install(IntPtr hWnd)
{
uint threadId;
uint processId;
if (hWnd == IntPtr.Zero)
{
threadId = (uint)AppDomain.GetCurrentThreadId();
throw new Exception("Lync thread not found!");
}
else
{
threadId = PInvoke.GetWindowThreadProcessId(hWnd, out processId);
}
//IntPtr module = PInvoke.GetModuleHandle(null);
//IntPtr module = PInvoke.GetModuleHandle(GetType().Module.FullyQualifiedName);
IntPtr module = PInvoke.GetModuleHandle("communicator.exe");
int error = PInvoke.GetLastError();
m_hhook = PInvoke.SetWindowsHookEx(
m_hookType,
m_filterFunc,
//Process.GetCurrentProcess().Handle,
//threadId);
//IntPtr.Zero,
//module,
//Marshal.GetHINSTANCE(
// System.Reflection.Assembly.GetExecutingAssembly().GetModules()[0]
// ).ToInt32()
module,
threadId);
//IntPtr hinst = Marshal.GetHINSTANCE(Process.GetCurrentProcess().Handle);
// http://msdn.microsoft.com/en-us/library/ms681385
// ERROR_HOOK_NEEDS_HMOD - 1428 = Cannot set nonlocal hook without a module handle
error = PInvoke.GetLastError();
}
You can't use GetModuleHandle for an external process. It must be a module that has been loaded into the current process.
I had the same issue: 126 = The specified module could not be found.
I added missing message loop into my app and it start working again.
I'm using Hook func like this:
hKeyboardHook = SetWindowsHookEx(
WH_KEYBOARD_LL,
KeyboardHookProcedure,
Marshal.GetHINSTANCE(typeof(your_class_type).Module),
0);
and I added Application.Run() at tne end of the Main func