Does somebody know how to unload a dll or any other type of module loaded by an external process?
I tried to do GetModuleHandle and then FreeLibrary with no result...
Thank you for all your replies
Thank you for all your replies. I found an interesting msdn article here :
http://blogs.msdn.com/b/jmstall/archive/2006/09/28/managed-create-remote-thread.aspx
The problem is that when i try to do a OpenProcess the external process crashes.
What are the minimum process access rights to unload a module from it ?
Here is what i am trying to do in c# :
[code]
protected const int PROCESS_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFF);
protected const int STANDARD_RIGHTS_REQUIRED = 0xF0000;
protected const int SYNCHRONIZE = 0x100000;
public static bool UnloadRemoteModule(FileEntry le)
{
try
{
Process process = System.Diagnostics.Process.GetProcessById(le.ProcessID);
if (process == null) return false;
StringBuilder sb = new StringBuilder(le.File);
UnloadModuleThreadProc umproc = new UnloadModuleThreadProc(UnloadModule);
IntPtr fpProc = Marshal.GetFunctionPointerForDelegate(umproc);
SafeProcessHandle processHandle = null;
IntPtr currentProcess = NativeMethods.GetCurrentProcess();
int processId = le.ProcessID;
bool remote = (processId != NativeMethods.GetProcessId(currentProcess));
try
{
if (remote)
{
MessageBox.Show("OPENING PROCESS !");
processHandle = NativeMethods.OpenProcess(PROCESS_ALL_ACCESS, true, processId);
System.Threading.Thread.Sleep(200);
uint dwThreadId;
if (processHandle.DangerousGetHandle() == IntPtr.Zero)
{
MessageBox.Show("COULD NOT OPEN HANDLE !");
}
else
{
// Create a thread in the first process.
IntPtr hThread = CreateRemoteThread(
processHandle.DangerousGetHandle(),
IntPtr.Zero,
0,
fpProc, IntPtr.Zero,
0,
out dwThreadId);
System.Threading.Thread.Sleep(200);
WaitForThreadToExit(hThread);
}
}
return true;
}
finally
{
if (remote)
{
if (processHandle != null)
{
processHandle.Close();
}
}
}
return false;
}
catch (Exception ex)
{
//Module.ShowError(ex);
return false;
}
}
public delegate int UnloadModuleThreadProc(IntPtr sb_module_name);
static int UnloadModule(IntPtr sb_module_name2)
{
using (StreamWriter sw = new StreamWriter(#"c:\a\logerr.txt"))
{
sw.AutoFlush = true;
sw.WriteLine("In Unload Module");
StringBuilder sb_module_name =new StringBuilder(#"C:\Windows\System32\MyDll.dll");
IntPtr mh = DetectOpenFiles.GetModuleHandle(sb_module_name.ToString());
sw.WriteLine("LAST ERROR="+Marshal.GetLastWin32Error().ToString());
sw.WriteLine("POINTER="+mh.ToInt32());
if (mh != IntPtr.Zero)
{
return (FreeLibrary(mh) ? 1 : 0);
}
sw.WriteLine("LAST ERROR 2 =" + Marshal.GetLastWin32Error().ToString());
sw.WriteLine("EXIT " + mh.ToInt32());
}
return 0;
}[/code]
You can do it, but honestly I must ask why? You're most likely going to screw things up beyond what you realize. Seriously, there's nothing that can go right if you do this. Don't read the rest of this post, close your browser, do some meditation, and figure out what you're doing wrong that made you ask this question.
HERE BE DRAGONS
That said, it can be done, and rather easily too.
All you have to do is use CreateRemoteThread, pass a handle to the process you want to force unload in, and a function pointer to a function that calls GetModuleHandle and FreeLibrary. Easy as pie.
Sample code (untested, written in vi, and not to be used no matter what):
DWORD WINAPI UnloadNamedModule(void *)
{
//If you value your life, don't use this code
LPCTSTR moduleName = _T("MYMODULE.DLL");
HMODULE module = GetModuleHandle(moduleName);
if (module != NULL)
{
UnloadModule(hModule);
//All hell breaks loose. Not even this comment will be reached.
//On your own head be it. Don't say I didn't warn you.
}
}
//Warning: this function should never be run!
void UnloadRemoteModule(HANDLE hProcess)
{
CreateRemoteThread(hProcess, NULL, 0, UnloadNamedModule, NULL, 0);
}
You cannot force an external process to unload it's modules. You would need to run that code from inside the external process. The best you can hope for is to kill the process that owns the external DLL. It would be extremely dangerous if you could unload a dll from an external process, the code could be running at the time that you pull it out of RAM.
If you are looking to replace the DLL, the best you can do is to rename the DLL and save the new one. That way, the DLL will get use the next time the external process loads it.
Correction to italics above: You can do it but you are asking for big trouble if you do. I still think the best approach is to do what I listed above, rename the DLL and put the new one in it's place for the next time the external process starts. It's a far safer approach if you would like to replace a DLL.
Related
A customer wants an overlay program that's always on top and that has 2 buttons that opens their programs.
If one of their programs is already open then my program should set their program on top of everything else (i.e switch to it and not open a new instance).
Essentially I find a process by the processname, then try to set it on top using the process, but it doesn't work for everything. For things like Notepad++ it works fine, but other programs that have have subprocesses it doesn't work, most likely because the main program starts child processes that I don't have access to?
I got the following code to find a process by processname, and send it on top in windows.
static Process FindProcess(string ProcessName)
{
Process[] targetProcesses = Process.GetProcessesByName(ProcessName);
Process targetProgram = null;
if(targetProcesses.Count() > 0)
{
targetProgram = targetProcesses[0];
}
return targetProgram;
}
Then in a later section I take the process, and try to put it on top using this code:
static void SendWindowToFront(Process SProcess)
{
try
{
AutomationElement aelement = AutomationElement.FromHandle(SProcess.MainWindowHandle);
if (aelement != null)
{
ShowWindow(SProcess.MainWindowHandle, SW_SHOWWINDOWED);
aelement.SetFocus();
}
}
catch (Exception ex)
{
Console.WriteLine("SendWindowToFront error: " + ex.Message);
}
}
But as I said, it doesn't work for all programs.
For example, the above program have processname "QuickDesign" (excuse the Swedish), but I can't use my code to switch to it, most likely because it creates a subprocess when starting that I don't have access to?
What I want to do with my program is essentially just the "Place above".
It's not specifically for that program in the picture, that's just an example I have to work.
I tried this code to find childprocesses, but it only returns an empty list:
public static class ProcessExtensions
{
public static IList<Process> GetChildProcesses(this Process process)
=> new ManagementObjectSearcher(
$"Select * From Win32_Process Where ParentProcessID={process.Id}")
.Get()
.Cast<ManagementObject>()
.Select(mo =>
Process.GetProcessById(Convert.ToInt32(mo["ProcessID"])))
.ToList();
}
Is this something that can be solved?
So I found an alternate way for this problem by following this guide:
http://weimenglee.blogspot.com/2007/01/programmatically-switch-to-another.html
Using the following code:
[DllImport("user32.dll")]
private static extern bool
SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern bool ShowWindowAsync(
IntPtr hWnd, int nCmdShow);
private const int SW_RESTORE = 9;
private void SwitchToProgram(string programName)
{
Process[] procs = Process.GetProcesses();
if (procs.Length != 0)
{
for (int i = 0; i < procs.Length; i++)
{
try
{
if (procs[i].MainModule.ModuleName ==
programName)
{
IntPtr hwnd =
procs[i].MainWindowHandle;
ShowWindowAsync(hwnd, SW_RESTORE);
SetForegroundWindow(hwnd);
return;
}
}
catch(Exception e)
{
Console.WriteLine("ERROR SwitchToProgram in loop: " + e.Message);
}
}
}
else
{
Console.WriteLine("ERROR SwitchToProgram: No processes running.");
return;
}
Console.WriteLine("ERROR SwitchToProgram: " + programName + " isn't running.");
}
I can just give a pathname like "programname.start" to the function and it will send it to the front if it finds it.
It works perfect on the customer computer, while slow at my own. But that's because my work computer has a bunch of restrictions that slows down everything a bit.
So we have a memory leak in our application and we think it's from WMI calls.
This is the code where we think is the leak:
private ThermalInfo()
{
// ============== Temperature
var mgmtTempScope = new ManagementScope(#"\root\WMI");
var oQuery = new ObjectQuery("select * from MSAcpi_ThermalZoneTemperature");
ManagementObjectSearcher oTempSearch = null;
ManagementObjectCollection collection = null;
try
{
oTempSearch = new ManagementObjectSearcher(mgmtTempScope, oQuery);
collection = oTempSearch.Get();
foreach (var obj in collection)
{
mTemperature = Convert.ToDouble(obj.Properties["CurrentTemperature"].Value) / 10 - 273.2;
mValid = true;
obj.Dispose();
}
}
catch //(Exception ex)
{
// Not supported
mTemperature = 0;
mValid = false;
}
finally
{
if (collection != null)
collection.Dispose();
if (oTempSearch != null)
oTempSearch.Dispose();
FlushMemory();
}
}
And here the FlushMemory():
[DllImportAttribute("kernel32.dll", EntryPoint = "SetProcessWorkingSetSize", ExactSpelling = true, CharSet = CharSet.Ansi, SetLastError = true)]
private static extern int SetProcessWorkingSetSize(IntPtr process, int minimumWorkingSetSize, int maximumWorkingSetSize);
public static void FlushMemory()
{
GC.Collect();
GC.WaitForPendingFinalizers();
if (Environment.OSVersion.Platform == PlatformID.Win32NT)
{
SetProcessWorkingSetSize(Process.GetCurrentProcess().Handle, -1, -1);
}
}
Our Application (it's actually a service) kept growing and growing - and the only thing that it was doing was calling this Method and setting the mTemperatur and mValid. With the FlushMemory Call the leak stopped and i could run the service the whole night without any growth in memory.
The only problem i have now is that the service won't let itself stop anymore. Everytime i want to stop the service it's never stopping and i always have to forcestop it with taskkill or the taskmanager.
Could someone please help me with this? Also how can i avoid the leak in the WMI calls? I've got w8.1 so there shouldn'T be a problem anymore but i guess there is...
we are seeing similar problem: ManagementClass, etc creates large memory leak, even with proper use of using(..){..} and Dispose().
Searching stackoverflow and elsewhere we see it is a common problem.
Calling GC.WaitForPendingFinalizers() once, which is part of the FlushMemory() above, is enough to fix it (GC.Collect() is not needed)
though we do not consider it a solution really, just a workaround.
There's a well-known problem that Skype on Windows 8 takes up 100% of one CPU core on some users' PCs. Including mine! There's a workaround courtesy of techfreak in Skype Community:
Download and run the latest version of process explorer. (http://download.sysinternals.com/files/ProcessExplorer.zip)
With Skype running search for Skype.exe in the list of active programs and double click on it.
Go to the threads tab and Suspend or Kill the Skype thread that is consuming the highest resources when IDLE. (like 50%+ CPU)
I'm getting annoyed with manually doing this after every reboot, so I'd like to automate the steps above, to write a simple C++ or C# "Skype launcher" program that does the following:
launch SKYPE.EXE
wake up every 1 second and look to see if one particular Skype thread is taking up over 98% of the CPU cycles in the process
if found, suspend that thread and exit the launcher process
otherwise loop up to 10 times until the bad thread is found.
After a quick Google search I got intimidated by the Win32 thread-enumeration APIs, and this "find and kill/suspend evil thread" problem seems to be fairly generic, so I'm wondering if there's an existing sample out there that I could re-purpose. Any pointers?
After much more googling and some dead ends with powershell (too many security hassles, too confusing for a newbie) and WMI (harder than needed), I finally found a great C# sample on MSDN Forums that will enumerate and suspend threads. This was easy to adapt to first check CPU time of each thread before suspending the culprit.
Here's code. Just compile and drop into your startup menu and Skype will no longer heat your office!
// code adapted from
// http://social.msdn.microsoft.com/Forums/en-US/d51efcf0-7653-403e-95b6-bf5fb97bf16c/suspend-thread-of-a-process
using System;
using System.Linq;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Threading;
using System.ComponentModel;
namespace SkypeLauncher
{
class Program
{
static void Main(string[] args)
{
Process[] procs = Process.GetProcessesByName("skype");
if (procs.Length == 0)
{
Console.WriteLine("Skype not loaded. Launching. ");
Process.Start(Environment.ExpandEnvironmentVariables(#"%PROGRAMFILES(X86)%\Skype\Phone\Skype.exe"));
Thread.Sleep(8000); // wait to allow skype to start up & get into steady state
}
// wait to allow skype to start up & get into steady state, where "steady state" means
// a lot of threads created
Process proc = null;
for (int i = 0; i < 50; i++)
{
procs = Process.GetProcessesByName("skype");
if (procs != null)
{
proc = procs[0];
if (proc.Threads.Count > 10)
break;
}
Thread.Sleep(1000); // wait to allow skype to start up & get into steady state
}
// try multiple times; if not hanging after a while, give up. It must not be hanging!
for (int i = 0; i < 50; i++)
{
// must reload process to get updated thread time info
procs = Process.GetProcessesByName("skype");
if (procs.Length == 0)
{
Console.WriteLine("Skype not loaded. Exiting. ");
return;
}
proc = procs[0];
// avoid case where exception thrown if thread is no longer around when looking at its CPU time, or
// any other reason why we can't read the time
var safeTotalProcessorTime = new Func<ProcessThread, double> (t =>
{
try { return t.TotalProcessorTime.TotalMilliseconds; }
catch (InvalidOperationException) { return 0; }
}
);
var threads = (from t in proc.Threads.OfType<ProcessThread>()
orderby safeTotalProcessorTime(t) descending
select new
{
t.Id,
t.ThreadState,
TotalProcessorTime = safeTotalProcessorTime(t),
}
).ToList();
var totalCpuMsecs = threads.Sum(t => t.TotalProcessorTime);
var topThread = threads[0];
var nextThread = threads[1];
var topThreadCpuMsecs = topThread.TotalProcessorTime;
var topThreadRatio = topThreadCpuMsecs / nextThread.TotalProcessorTime;
// suspend skype thread that's taken a lot of CPU time and
// and it has lots more CPU than any other thread.
// in other words, it's been ill-behaved for a long time!
// it's possible that this may sometimes suspend the wrong thread,
// but I haven't seen it break yet.
if (topThreadCpuMsecs > 10000 && topThreadRatio > 5)
{
Console.WriteLine("{0} bad thread. {0:N0} msecs CPU, {1:N1}x CPU than next top thread.",
topThread.ThreadState == System.Diagnostics.ThreadState.Wait ? "Already suspended" : "Suspending",
topThreadCpuMsecs,
topThreadRatio);
Thread.Sleep(1000);
IntPtr handle = IntPtr.Zero;
try
{
//Get the thread handle & suspend the thread
handle = OpenThread(2, false, topThread.Id);
var success = SuspendThread(handle);
if (success == -1)
{
Win32Exception ex = new Win32Exception(Marshal.GetLastWin32Error());
Console.WriteLine(ex.Message);
}
Console.WriteLine("Exiting");
Thread.Sleep(1000);
return;
}
finally
{
if (handle != IntPtr.Zero)
CloseHandle(handle);
};
}
Console.WriteLine("Top thread: {0:N0} msecs CPU, {1:N1}x CPU than next top thread. Waiting.",
topThreadCpuMsecs,
topThreadRatio);
Thread.Sleep(2000); // wait between tries
}
Console.WriteLine("No skype thread is ill-behaved enough. Giving up.");
}
[DllImport("kernel32.dll", SetLastError = true)]
private static extern int SuspendThread(IntPtr hThread);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CloseHandle(IntPtr handle);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern
IntPtr OpenThread(int dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)]bool bInheritHandle, int dwThreadId);
}
}
We have a third party winforms software that we need to run as a batch
I need to monitor if a certain form for a certain process (we run several processes at the same time) is shown.
I have used this method to get all window handles for a process
public IEnumerable<int> EnumerateProcessWindowHandles(int processId)
{
var handles = new List<IntPtr>();
try
{
foreach (ProcessThread thread in Process.GetProcessById(processId).Threads)
Win32.EnumThreadWindows(thread.Id,
(hWnd, lParam) => { handles.Add(hWnd); return true; }, IntPtr.Zero);
}
catch(Exception e) {}
return handles.Select(h => (int)h);
}
Then this method to get the window caption from the hwnd
public string GetTitle(int hwnd)
{
int length = Win32.SendMessage((IntPtr)hwnd, Win32.WM_GETTEXTLENGTH, 0, IntPtr.Zero);
var sb = new StringBuilder(length + 1);
Win32.SendMessage((IntPtr)hwnd, Win32.WM_GETTEXT, (IntPtr)sb.Capacity, sb);
return sb.ToString();
}
Each second I poll the process with above methods, but sometimes it fails to detected a window shown. The window in question is opened more than a second so its not the pol frequency.
Is there a more reliable way of getting callbacks when a window is closed/opened?
Probably the cleanest way to listen to window creation and destruction is using a CBT hook. Listen for HCBT_CREATEWND and HCBT_DESTROYWND. This MSDN article, Windows Hooks in the .NET Framework, covers the subject from a .net perspective.
maybe that can help
[1] http://spradip.wordpress.com/category/programming-c/page/2/
and this any ms C++ example
[2] http://msdn.microsoft.com/en-us/library/windows/desktop/ms686701(v=vs.85).aspx
I'm currently writing a software in Visual Studio 2012 for communication with RFID-cards.
I got a DLL written in Delphi to handle the communication with the card reader.
The problem is: My software is running fine on machines, that have VS2012 installed. On other systems it freezes itself or the whole system.
I tried it on Win XP / 7 / 8 with x32 and x64 configuration.
I'm using .NET 4.0.
After connecting to the reader, the software starts a backgroundWorker, which polls (at 200ms rate) the reader with a command to inventory cards in the readers RF-field. The crash usally happens ca. 10 to 20 seconds after the reader connect. Here is the code:
[DllImport("tempConnect.dll", CallingConvention = CallingConvention.StdCall)]
private static extern int inventory(int maxlen, [In] ref int count,
IntPtr UIDs, UInt32 HFOffTime);
public String getCardID()
{
if (isConnectet())
{
IntPtr UIDs = IntPtr.Zero;
int len = 2 * 8;
Byte[] zero = new Byte[len];
UIDs = Marshal.AllocHGlobal(len);
Thread.Sleep(50);
Marshal.Copy(zero, 0, UIDs, len);
int count = 0;
int erg;
String ret;
try
{
erg = inventory(len, ref count, UIDs, 50);
}
catch (ExternalException) // this doesn't catch anything (iI have set <legacyCorruptedStateExceptionsPolicy enabled="true"/>)
{
return "\0";
}
finally
{
ret = Marshal.PtrToStringAnsi(UIDs, len);
IntPtr rslt = LocalFree(UIDs);
GC.Collect();
}
if (erg == 0)
return ret;
else
return zero.ToString();
}
else
return "\0";
}
The DLL is written in Delphi, the code DLL command is:
function inventory (maxlen: Integer; var count: Integer;
UIDs: PByteArray; HFOffTime: Cardinal = 50): Integer; STDCALL;
I think there may be a memory leak somewhere, but I have no idea how to find it...
EDIT:
I added some ideas (explicit GC.Collect(), try-catch-finally) to my code above, but it still doesnt work.
Here is the code, that calls getCardID():
The action, that runs every 200ms:
if (!bgw_inventory.IsBusy)
bgw_inventory.RunWorkerAsync();
Async backgroundWorker does:
private void bgw_inventory_DoWork(object sender, DoWorkEventArgs e)
{
if (bgw_inventory.CancellationPending)
{
e.Cancel = true;
return;
}
else
{
String UID = reader.getCardID();
if (bgw_inventory.CancellationPending)
{
e.Cancel = true;
return;
}
if (UID.Length == 16 && UID.IndexOf("\0") == -1)
{
setCardId(UID);
if (!allCards.ContainsKey(UID))
{
allCards.Add(UID, new Card(UID));
}
if (readCardActive || deActivateCardActive || activateCardActive)
{
if (lastActionCard != UID)
actionCard = UID;
else
setWorkingStatus("OK", Color.FromArgb(203, 218, 138));
}
}
else
{
setCardId("none");
if (readCardActive || deActivateCardActive || activateCardActive)
setWorkingStatus("waiting for next card", Color.Yellow);
}
}
}
EDIT
Till now I have made some little reworks (updates above) at the code. Now only the App. crashes with 0xC00000FD (Stack overflow) at "tempConnect.dll". This does not happen on Systems with VS2012 installed or if I use the DLL with native Delphi!
Do anyone have any other ideas ?
EDIT
Now I made the DLL logging it's stacksize and found something weird:
If it's called and polled from my C# Programm, the stacksize is changing continuously up and down.
If i do the same from a natural Deplhi Program the stacksize is constant!
So I'll do further investigations, but I have no really idea, what I have to search for...
I'm a little concerned about how're using that Marshal object. As you fear with the memory leak, it seems to be allocating memory quite often but I don't see it ever explicitly releasing it. The garbage collector should (operative word) be taking care of that, but you say yourself you have some unmanaged code in the mix. It is difficult with the posted information to tell where the unmanaged code begins.
Check out this question for some good techniques to finding memory leaks in .NET itself - this will give you a ton of information on how memory is being used in the managed end of your code (that is, the part you can directly control). Use the Windows Performance Monitor with breakpoints to keep an eye on the overall health of the system. If .NET appears to be behaving, but WPM is showing some sharp spikes, it's probably in the unmanaged code. You can't really control anything but your usage there, so it would probably be time to go back to the documentation at that point.