将 .NET COM Interop 程序集与其托管进程断开

发布于 2024-08-06 01:27:38 字数 546 浏览 6 评论 0原文

当 ActiveXObject 托管在 Windows 桌面/边栏小工具中时,该 ActiveXObject 会被缓存,并且它的 DLL 文件会被锁定(这意味着它无法移动、删除或重命名)。问题是这样的;当该小工具随后关闭时,DLL 仍被 Windows 边栏锁定并且无法删除。这会导致一个严重的问题,即新版本的小工具无法安装在以前版本的小工具之上,在删除它的过程中会失败,并且不会出现任何错误消息。

这对于用户来说不是很友好,因此我正在寻找一种在小工具卸载事件期间以某种方式“切断”与 ActiveX 控件的联系的方法。我希望有人能告诉我这是否可行,如果可行,请给我一些关于如何实现它的想法。

仅供参考,Windows 边栏小工具实际上只是 Internet Explorer 服务器窗口,因此可以安全地假设 IE 表现出相同的行为。

编辑: Unlocker 似乎做了我需要做的事情,那么我怎样才能在.NET中以编程方式实现同​​样的事情呢?

When an ActiveXObject is hosted in a Windows Desktop/Sidebar Gadget, that ActiveXObject is sort of cached and the DLL file for it is locked (meaning it cannot be moved, deleted or renamed). The problem is this; when the gadget is subsequently closed, the DLL is still locked by Windows Sidebar and it cannot be removed. This causes a significant problem whereby a new version of the gadget cannot be installed over the top of a previous version of the gadget, it fails during the process of deleting it without any error messages.

This isn't very user-friendly, so I'm looking for a way to "sever" ties to the ActiveX control somehow during the gadget's unload event. I'm hoping someone can tell me whether or not this is possible and if it is give me some ideas on how to implement it.

FYI, Windows Sidebar Gadgets are actually just Internet Explorer server windows, so it's probably safe to assume IE exhibits the same behavior.

EDIT: Unlocker seems to do pretty much what I need to do, so how can I achieve the same thing programmatically in .NET?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

温柔戏命师 2024-08-13 01:27:38

好吧,这是一个相当复杂的问题。我以前见过这种行为,我不熟悉 Windows 桌面/侧边栏小工具,因为我不使用它。不过,我已经设法想出了三种可能的攻击方法

1。 来自 TechNet 的句柄

这不是我的主意, 还有另一个 StackOverflow 线程 推荐这个方法。但我对这是否有效持怀疑态度。文件锁(该实用程序处理的内容)和“加载库”锁之间存在差异,我认为这就是您在使用 ActiveX 时遇到的问题。

我稍微修改了该线程的代码,他们使用 Process.Kill() 来释放锁,我认为最好使用handle.exe 来释放锁。

public struct LockInfo
{
    public int PID;
    public string Handle;

    public LockInfo(int pid, string handle)
    {
        this.PID = pid;
        this.Handle = handle;
    }
}      

static List<LockInfo> getLockingInfo(string fileName)
{            
    List<LockInfo> lockingProcesses = new List<LockInfo>();

    Process tool = new Process();
    tool.StartInfo.FileName = "handle.exe";
    tool.StartInfo.Arguments = fileName;
    tool.StartInfo.UseShellExecute = false;
    tool.StartInfo.RedirectStandardOutput = true;
    tool.Start();
    tool.WaitForExit();
    string outputTool = tool.StandardOutput.ReadToEnd();

    // I;m not so hot with regex, so a bit of regex and a bit of manual splitting
    string matchPattern = @"(?<=\s+pid:\s+)\b(\d+)\b(\s+)\b(\S+:)";
    foreach (Match match in Regex.Matches(outputTool, matchPattern))
    {
        string[] temp = match.Value.Replace(":", "").Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
        if (temp.Length == 2)
        {
            lockingProcesses.Add(new LockInfo(int.Parse(temp[0].Trim()), temp[1].Trim()));
        }
    }
    return lockingProcesses.Count > 0 ? lockingProcesses : null;
}

static bool closeFileHandle(List<LockInfo> lockingInfo)
{
    if ((lockingInfo == null) || (lockingInfo.Count == 0))
    {
        throw new ArgumentException("lockingProcesses cannot be null or empty");
    }

    bool fileClosed = true;

    foreach (LockInfo lockInfo in lockingInfo)
    {
        Process tool = new Process();
        tool.StartInfo.FileName = "handle.exe";
        tool.StartInfo.Arguments = string.Format("-c {0} -y -p {1}", lockInfo.Handle, lockInfo.PID.ToString());
        tool.StartInfo.UseShellExecute = false;
        tool.StartInfo.RedirectStandardOutput = true;
        tool.Start();
        tool.WaitForExit();
        string outputTool = tool.StandardOutput.ReadToEnd();
        if (outputTool.IndexOf("Handle closed") == -1)
        {
            fileClosed = false;
        }
    }
    return fileClosed;
}

public static void Main()
{            
    //Path to locked file, make sure the full path is in quotes
    string fileName = "\"" + @"C:\Your_Path\To_The\ActiveX.ocx" + "\"";
    List<LockInfo> lockInfo = getLockingInfo(fileName);
    if ((lockInfo != null) && (lockInfo.Count > 0))
    {
        closeFileHandle(lockInfo);
    }                                 
}

...


2。 Win32 风格

互联网上没有太多关于此的信息,并且似乎需要一些未记录的 api 调用才能顺利实现此目的。

我这些 C++ 示例可能会有所帮助。

不幸的是我无法让它无缝工作。我已经使用 MS Word 中加载的 ActiveX 测试了此方法。然后我尝试解锁ActiveX,它不是很稳定,经常导致word崩溃。我想我没有正确破译上述程序所需的 C++ 战争创伤。

连同 CreateRemoteThread in C# 的示例一起,我确实将这段代码放在一起。

public struct ProcessInfo
{
    public Process Process;
    public ProcessModule Module;

    public ProcessInfo(Process process, ProcessModule module)
    {
        this.Process = process;
        this.Module = module;
    }
}

private static List<ProcessInfo> getProcessInfo(string fileName, bool partialMatch)
{
    List<ProcessInfo> myProcesses = new List<ProcessInfo>();

    Process[] runningProcesses = Process.GetProcesses();
    int i = 0;
    for (i = 0; i < runningProcesses.Length; i++)
    {
        Process currentProcess = runningProcesses[i];
        try
        {
            if (!currentProcess.HasExited)
            {
                try
                {
                    ProcessModuleCollection modules = currentProcess.Modules;
                    int j = 0;
                    for (j = 0; j < modules.Count; j++)
                    {
                        if (partialMatch)
                        {
                            if ((modules[j].FileName.ToLower().IndexOf(fileName.ToLower()) != -1))
                            {
                                myProcesses.Add(new ProcessInfo(currentProcess, modules[j]));
                                break;
                            }
                        }
                        else
                        {
                            if ((modules[j].FileName.ToLower().CompareTo(fileName.ToLower()) == 0))
                            {
                                myProcesses.Add(new ProcessInfo(currentProcess, modules[j]));
                                break;
                            }
                        }
                    }
                }
                catch (NotSupportedException)
                {
                    // You are attempting to access the Modules property for a process that is running on a remote computer. 
                    // This property is available only for processes that are running on the local computer. 
                }
                catch (InvalidOperationException)
                {
                    // The process Id is not available.
                }
                catch (Win32Exception)
                {
                    // You are attempting to access the Modules property for either the system process or the idle process. 
                    // These processes do not have modules.
                }
            }
        }
        catch (InvalidOperationException)
        {
            // There is no process associated with the object. 
        }
        catch (Win32Exception)
        {
            // The exit code for the process could not be retrieved. 
        }
        catch (NotSupportedException)
        {
            // You are trying to access the HasExited property for a process that is running on a remote computer.
            // This property is available only for processes that are running on the local computer.

        }
    }
    return myProcesses.Count > 0 ? myProcesses : null;
}

private static void forceRemoteCloseHandle(ProcessInfo processInfo)
{
    // Open remote process for write
    IntPtr hProcess = NativeMethods.OpenProcess(NativeMethods.PROCESS_CREATE_THREAD | NativeMethods.PROCESS_VM_OPERATION |
            NativeMethods.PROCESS_VM_WRITE | NativeMethods.PROCESS_VM_READ, false, processInfo.Process.Id);

    // Get the handle to CloseHandle in kernel32.dll
    IntPtr hKernel32 = NativeMethods.LoadLibrary("kernel32.dll");
    IntPtr hCloseHandle = NativeMethods.GetProcAddress(hKernel32, "CloseHandle");
    uint temp = 0;

    // Create the remote thread and point it to CloseHandle
    IntPtr hCreateRemoteThread = NativeMethods.CreateRemoteThread((IntPtr)hProcess, (IntPtr)0, 0, hCloseHandle, (IntPtr)processInfo.Module.BaseAddress, 0, out temp);

    // Wait for thread to end
    NativeMethods.WaitForSingleObject(hCreateRemoteThread, 2000);

    //Closes the remote thread handle
    NativeMethods.CloseHandle(hCreateRemoteThread);

    //Free up the kernel32.dll
    if (hKernel32 != null)
        NativeMethods.FreeLibrary(hKernel32);

    //Close the process handle
    NativeMethods.CloseHandle(hProcess);
}

private static void forceRemoteFreeLibrary(ProcessInfo processInfo)
{
    // Open remote process for write
    IntPtr hProcess = NativeMethods.OpenProcess(NativeMethods.PROCESS_CREATE_THREAD | NativeMethods.PROCESS_VM_OPERATION |
            NativeMethods.PROCESS_VM_WRITE | NativeMethods.PROCESS_VM_READ, false, processInfo.Process.Id);

    // Get the handle to FreeLibrary in kernel32.dll
    IntPtr hKernel32 = NativeMethods.LoadLibrary("kernel32.dll");
    IntPtr hFreeHandle = NativeMethods.GetProcAddress(hKernel32, "FreeLibrary");

    // Create the remote thread and point it to FreeLibrary
    uint temp = 0;
    IntPtr hCreateRemoteThread = NativeMethods.CreateRemoteThread((IntPtr)hProcess, (IntPtr)0, 0, hFreeHandle, (IntPtr)processInfo.Module.BaseAddress, 0, out temp);

    // Wait for thread to end
    NativeMethods.WaitForSingleObject(hCreateRemoteThread, 2000);

    //Closes the remote thread handle
    NativeMethods.CloseHandle(hCreateRemoteThread);

    //Free up the kernel32.dll
    if (hKernel32 != null)
        NativeMethods.FreeLibrary(hKernel32);

    // Close the process handle
    NativeMethods.CloseHandle(hProcess);        
}

public static void Main()
{
    string strFile = @"C:\Program Files\Microsoft Office\OFFICE11\MSCAL.OCX";
    List<ProcessInfo> lockingProcesses = getProcessInfo(strFile, false);

    foreach (ProcessInfo processInfo in lockingProcesses)
    {
        forceRemoteCloseHandle(processInfo);
        // OR
        forceRemoteFreeLibrary(processInfo);
    }

    // OR
    foreach (ProcessInfo procInfo in lockingProcesses)
    {
        procInfo.Process.Kill();
    }

}

internal static class NativeMethods
{
    internal const int PROCESS_TERMINATE = 0x0001;
    internal const int PROCESS_CREATE_THREAD = 0x0002;
    internal const int PROCESS_VM_OPERATION = 0x0008;
    internal const int PROCESS_VM_READ = 0x0010;
    internal const int PROCESS_VM_WRITE = 0x0020;

    internal const int PROCESS_QUERY_INFORMATION = 0x0400;

    [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
    internal static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);

    [DllImport("kernel32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
    internal static extern IntPtr GetProcAddress(IntPtr hModule, string procName);

    [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
    internal static extern int WaitForSingleObject(IntPtr hHandle, int dwMilliseconds);

    [DllImport("kernel32", SetLastError = true)]
    internal static extern IntPtr LoadLibrary(string lpFileName);


    [DllImport("kernel32.dll", SetLastError = true)]
    internal static extern bool FreeLibrary(IntPtr hModule);

    [DllImport("kernel32")]
    public static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, out uint lpThreadId);

    [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
    internal static extern int CloseHandle(IntPtr hPass);
}

...


3。只需使用 Unlocker

这是我最好的建议。来自 technet 的句柄无法处理加载的 dll/ocx 锁(根据我的测试)。 Win32 是混乱且无文档的。

Unlocker 提供命令行访问,因此您可以按照与handle.exe 完全相同的方式调用它。只是搞怪一个/?在unlocker.exe之后在命令提示符下查看开关。

还有便携式版本的 Unlocker 可用,以便您可以将其捆绑到您的部署中,而无需强制最终用户安装该应用程序。

如果其他方法都失败,您可以联系 Unlocker 的作者,从他的自述文件中查看此内容。

许可

如果你有兴趣
重新分发 Unlocker,无论是在
原始或修改形式,或希望
在产品中使用Unlocker源代码,
请发送电子邮件至
[电子邮件受保护],包含详细信息。

...


4。使用 Process Hacker 共享库

我刚刚发现了这个出色的工具:Process Hacker 这是用 100% C# 代码编写(尽管它在底层确实通过 P/Invoke 使用了许多 WinAPI 函数)。

最好的一点是:它是开源的(LGPL),并提供了两个开发人员可以在其解决方案中引用的库:ProcessHacker.Common ProcessHacker.Native。

我下载了源代码,只是警告一句,这是一个相当大的解决方案,因此可能需要一些时间才能弄清楚到底什么/如何使用它。

它使用我在选项 2 中谈到的未记录的 API 函数 (ntdll.dl),并且可以执行 Unlocker 可以执行的所有操作,甚至更多。

Okay this is a rather complex problem. I have seen this behavior before, I'm not familiar with the Windows Desktop/Sidebar Gadget as I don't use it. However I've managed to come up with three possible methods of attack

1. Handle from TechNet

This wasn't my idea, there is another StackOverflow thread that recommends this method. However I'm skeptical as to whether or not this will work. There is a difference between a file lock (what this utility handles) and a "loaded library" lock which is what I assume is the problem you are having with ActiveX.

I modified the code from that thread slightly, there they use Process.Kill() to release the lock, I would think it's better to use handle.exe to release the lock.

public struct LockInfo
{
    public int PID;
    public string Handle;

    public LockInfo(int pid, string handle)
    {
        this.PID = pid;
        this.Handle = handle;
    }
}      

static List<LockInfo> getLockingInfo(string fileName)
{            
    List<LockInfo> lockingProcesses = new List<LockInfo>();

    Process tool = new Process();
    tool.StartInfo.FileName = "handle.exe";
    tool.StartInfo.Arguments = fileName;
    tool.StartInfo.UseShellExecute = false;
    tool.StartInfo.RedirectStandardOutput = true;
    tool.Start();
    tool.WaitForExit();
    string outputTool = tool.StandardOutput.ReadToEnd();

    // I;m not so hot with regex, so a bit of regex and a bit of manual splitting
    string matchPattern = @"(?<=\s+pid:\s+)\b(\d+)\b(\s+)\b(\S+:)";
    foreach (Match match in Regex.Matches(outputTool, matchPattern))
    {
        string[] temp = match.Value.Replace(":", "").Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
        if (temp.Length == 2)
        {
            lockingProcesses.Add(new LockInfo(int.Parse(temp[0].Trim()), temp[1].Trim()));
        }
    }
    return lockingProcesses.Count > 0 ? lockingProcesses : null;
}

static bool closeFileHandle(List<LockInfo> lockingInfo)
{
    if ((lockingInfo == null) || (lockingInfo.Count == 0))
    {
        throw new ArgumentException("lockingProcesses cannot be null or empty");
    }

    bool fileClosed = true;

    foreach (LockInfo lockInfo in lockingInfo)
    {
        Process tool = new Process();
        tool.StartInfo.FileName = "handle.exe";
        tool.StartInfo.Arguments = string.Format("-c {0} -y -p {1}", lockInfo.Handle, lockInfo.PID.ToString());
        tool.StartInfo.UseShellExecute = false;
        tool.StartInfo.RedirectStandardOutput = true;
        tool.Start();
        tool.WaitForExit();
        string outputTool = tool.StandardOutput.ReadToEnd();
        if (outputTool.IndexOf("Handle closed") == -1)
        {
            fileClosed = false;
        }
    }
    return fileClosed;
}

public static void Main()
{            
    //Path to locked file, make sure the full path is in quotes
    string fileName = "\"" + @"C:\Your_Path\To_The\ActiveX.ocx" + "\"";
    List<LockInfo> lockInfo = getLockingInfo(fileName);
    if ((lockInfo != null) && (lockInfo.Count > 0))
    {
        closeFileHandle(lockInfo);
    }                                 
}

...


2. Win32 Style

There isn't a lot of info on the internets about this, and it would seem there are some undocumented api calls that are needed to pull this off smoothly.

I these c++ examples might help.

Unfortunately I couldn't get this to work seamlessly. I have tested this method using an ActiveX loaded in MS Word. I then tried to unlock the ActiveX, it's not very stable and often caused word to crash. I guess I don't have the required c++ war wounds to decipher the above programs correctly.

Along with this example of CreateRemoteThread in C# I did put this code together.

public struct ProcessInfo
{
    public Process Process;
    public ProcessModule Module;

    public ProcessInfo(Process process, ProcessModule module)
    {
        this.Process = process;
        this.Module = module;
    }
}

private static List<ProcessInfo> getProcessInfo(string fileName, bool partialMatch)
{
    List<ProcessInfo> myProcesses = new List<ProcessInfo>();

    Process[] runningProcesses = Process.GetProcesses();
    int i = 0;
    for (i = 0; i < runningProcesses.Length; i++)
    {
        Process currentProcess = runningProcesses[i];
        try
        {
            if (!currentProcess.HasExited)
            {
                try
                {
                    ProcessModuleCollection modules = currentProcess.Modules;
                    int j = 0;
                    for (j = 0; j < modules.Count; j++)
                    {
                        if (partialMatch)
                        {
                            if ((modules[j].FileName.ToLower().IndexOf(fileName.ToLower()) != -1))
                            {
                                myProcesses.Add(new ProcessInfo(currentProcess, modules[j]));
                                break;
                            }
                        }
                        else
                        {
                            if ((modules[j].FileName.ToLower().CompareTo(fileName.ToLower()) == 0))
                            {
                                myProcesses.Add(new ProcessInfo(currentProcess, modules[j]));
                                break;
                            }
                        }
                    }
                }
                catch (NotSupportedException)
                {
                    // You are attempting to access the Modules property for a process that is running on a remote computer. 
                    // This property is available only for processes that are running on the local computer. 
                }
                catch (InvalidOperationException)
                {
                    // The process Id is not available.
                }
                catch (Win32Exception)
                {
                    // You are attempting to access the Modules property for either the system process or the idle process. 
                    // These processes do not have modules.
                }
            }
        }
        catch (InvalidOperationException)
        {
            // There is no process associated with the object. 
        }
        catch (Win32Exception)
        {
            // The exit code for the process could not be retrieved. 
        }
        catch (NotSupportedException)
        {
            // You are trying to access the HasExited property for a process that is running on a remote computer.
            // This property is available only for processes that are running on the local computer.

        }
    }
    return myProcesses.Count > 0 ? myProcesses : null;
}

private static void forceRemoteCloseHandle(ProcessInfo processInfo)
{
    // Open remote process for write
    IntPtr hProcess = NativeMethods.OpenProcess(NativeMethods.PROCESS_CREATE_THREAD | NativeMethods.PROCESS_VM_OPERATION |
            NativeMethods.PROCESS_VM_WRITE | NativeMethods.PROCESS_VM_READ, false, processInfo.Process.Id);

    // Get the handle to CloseHandle in kernel32.dll
    IntPtr hKernel32 = NativeMethods.LoadLibrary("kernel32.dll");
    IntPtr hCloseHandle = NativeMethods.GetProcAddress(hKernel32, "CloseHandle");
    uint temp = 0;

    // Create the remote thread and point it to CloseHandle
    IntPtr hCreateRemoteThread = NativeMethods.CreateRemoteThread((IntPtr)hProcess, (IntPtr)0, 0, hCloseHandle, (IntPtr)processInfo.Module.BaseAddress, 0, out temp);

    // Wait for thread to end
    NativeMethods.WaitForSingleObject(hCreateRemoteThread, 2000);

    //Closes the remote thread handle
    NativeMethods.CloseHandle(hCreateRemoteThread);

    //Free up the kernel32.dll
    if (hKernel32 != null)
        NativeMethods.FreeLibrary(hKernel32);

    //Close the process handle
    NativeMethods.CloseHandle(hProcess);
}

private static void forceRemoteFreeLibrary(ProcessInfo processInfo)
{
    // Open remote process for write
    IntPtr hProcess = NativeMethods.OpenProcess(NativeMethods.PROCESS_CREATE_THREAD | NativeMethods.PROCESS_VM_OPERATION |
            NativeMethods.PROCESS_VM_WRITE | NativeMethods.PROCESS_VM_READ, false, processInfo.Process.Id);

    // Get the handle to FreeLibrary in kernel32.dll
    IntPtr hKernel32 = NativeMethods.LoadLibrary("kernel32.dll");
    IntPtr hFreeHandle = NativeMethods.GetProcAddress(hKernel32, "FreeLibrary");

    // Create the remote thread and point it to FreeLibrary
    uint temp = 0;
    IntPtr hCreateRemoteThread = NativeMethods.CreateRemoteThread((IntPtr)hProcess, (IntPtr)0, 0, hFreeHandle, (IntPtr)processInfo.Module.BaseAddress, 0, out temp);

    // Wait for thread to end
    NativeMethods.WaitForSingleObject(hCreateRemoteThread, 2000);

    //Closes the remote thread handle
    NativeMethods.CloseHandle(hCreateRemoteThread);

    //Free up the kernel32.dll
    if (hKernel32 != null)
        NativeMethods.FreeLibrary(hKernel32);

    // Close the process handle
    NativeMethods.CloseHandle(hProcess);        
}

public static void Main()
{
    string strFile = @"C:\Program Files\Microsoft Office\OFFICE11\MSCAL.OCX";
    List<ProcessInfo> lockingProcesses = getProcessInfo(strFile, false);

    foreach (ProcessInfo processInfo in lockingProcesses)
    {
        forceRemoteCloseHandle(processInfo);
        // OR
        forceRemoteFreeLibrary(processInfo);
    }

    // OR
    foreach (ProcessInfo procInfo in lockingProcesses)
    {
        procInfo.Process.Kill();
    }

}

internal static class NativeMethods
{
    internal const int PROCESS_TERMINATE = 0x0001;
    internal const int PROCESS_CREATE_THREAD = 0x0002;
    internal const int PROCESS_VM_OPERATION = 0x0008;
    internal const int PROCESS_VM_READ = 0x0010;
    internal const int PROCESS_VM_WRITE = 0x0020;

    internal const int PROCESS_QUERY_INFORMATION = 0x0400;

    [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
    internal static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);

    [DllImport("kernel32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
    internal static extern IntPtr GetProcAddress(IntPtr hModule, string procName);

    [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
    internal static extern int WaitForSingleObject(IntPtr hHandle, int dwMilliseconds);

    [DllImport("kernel32", SetLastError = true)]
    internal static extern IntPtr LoadLibrary(string lpFileName);


    [DllImport("kernel32.dll", SetLastError = true)]
    internal static extern bool FreeLibrary(IntPtr hModule);

    [DllImport("kernel32")]
    public static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, out uint lpThreadId);

    [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
    internal static extern int CloseHandle(IntPtr hPass);
}

...


3. Just use Unlocker

This is my best recommendation. Handle from technet can't handle loaded dll/ocx locks (under my tests). Win32 is messy and undocumented.

Unlocker provides command line access so you can call it in exactly the same way as handle.exe. Just wack a /? after unlocker.exe in a command prompt to see the switches.

There is also a portable version of Unlocker available so you can bundle it into your deployment without forcing the end users to install the app.

If all else fails you could contact the author of Unlocker, check out this from his readme.

Licensing

If you are interested in
redistributing Unlocker, either in
original or modified form, or wish to
use Unlocker source code in a product,
please send e-mail to
[email protected] with details.

...


4. Use Process Hacker Shared Libraries

I just discovered this brilliant tool: Process Hacker which is written in 100% C# code (although it does use a lot of WinAPI functions via P/Invoke under the hood).

The best thing about this:it's open source (LGPL'd) and provides two libraries that developers can reference in their solutions: ProcessHacker.Common ProcessHacker.Native.

I downloaded the source and just a word of warning it's a pretty big solution so may take a bit of time to figure out exactly what/how to use it.

It uses the undocumented API functions (ntdll.dl) I spoke about in option 2 and can do everything Unlocker can and a whole lot more.

与往事干杯 2024-08-13 01:27:38

不确定这是否适用于 ActiveX 对象,但它确实适用于 .NET 程序集。我将它用于单元测试,其中 DLL 必须顺利覆盖。使用的机制是卷影复制

从应用程序外部关闭句柄似乎并不是一个非常安全的选择。

这不是解决方案,也许是一个想法或方向......

Not sure if this works for ActiveX objects but it definitively does for .NET assemblies. I use it for UnitTesting where the DLLs have to be overwritten smoothly. The mechanism used is shadow copying.

Closing handles from outside an application seems not really a very safe option.

It is not the solution maybe an idea or direction...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文