Domanda

Quando un ActiveXObject è ospitato in un desktop di Windows / Sidebar Gadget, che è una sorta di ActiveXObject memorizzato nella cache e il file DLL per esso è bloccato (il che significa che non può essere spostato, cancellato o rinominato). Il problema è questo; quando il gadget viene successivamente chiuso, la DLL è ancora bloccato da Windows Sidebar e non può essere rimosso. Ciò causa un problema significativo per cui una nuova versione del gadget non può essere installato sopra la parte superiore di una versione precedente del gadget, non riesce durante il processo di eliminazione senza alcun messaggio di errore.

Questo non è molto user-friendly, quindi sono alla ricerca di un modo per "tagliare" legami con il controllo ActiveX in qualche modo durante l'evento di scaricamento del gadget. Sto sperando che qualcuno mi può dire se questo è possibile e se si tratta di darmi alcune idee su come implementarlo.

Cordiali saluti, Windows Sidebar Gadgets sono in realtà solo di Windows Server di Internet Explorer, quindi è probabilmente lecito ritenere IE presenta lo stesso comportamento.

Modifica Unlocker sembra di fare più o meno quello che mi serve da fare, così come posso ottenere la stessa cosa a livello di codice in .NET?

È stato utile?

Soluzione

Va bene che questo è un problema piuttosto complesso. Ho visto questo comportamento prima, io non sono a conoscenza del desktop di Windows / Sidebar Gadget come io non lo uso. Comunque sono riuscito a venire con tre possibili metodi di attacco

1. Maneggiare da TechNet

Questa non era la mia idea, c'è un altro filo StackOverflow che raccomanda questo metodo. Comunque io sono scettico sul fatto o no questo lavoro. C'è una differenza tra un blocco di file (quello che gestisce questo programma di utilità) e una serratura "libreria di carico", che è quello che presumo è il problema riscontrato con ActiveX.

Ho modificato il codice da quel filo un po ', ci usano Process.Kill () per rilasciare il blocco, io penso che sia meglio usare handle.exe per rilasciare il blocco.

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 Stile

Non c'è un sacco di informazioni sulle internet su questo, e sembrerebbe ci sono alcune chiamate API non documentate che sono necessari per tirare fuori questo senza intoppi.

I questi c ++ esempi possono aiutare.

Purtroppo non ho potuto ottenere questo a lavorare senza problemi. Ho testato questo metodo che utilizza un ActiveX caricati in MS Word. Allora ho provato a sbloccare l'ActiveX, non è molto stabile e parola spesso causato il crash. Credo di non avere i c ferite di guerra richiesti ++ per decifrare correttamente i programmi di cui sopra.

Con questo esempio di CreateRemoteThread in C # ho messo questo codice insieme.

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. Basta usare Unlocker

Questa è la mia migliore raccomandazione. Maniglia da TechNet non può gestire caricati serrature dll / ocx (sotto i miei test). Win32 è disordinato e non documentata.

Unlocker offre accesso alla linea di comando in modo da poter chiamare esattamente nello stesso modo in cui handle.exe. Basta wack un /? dopo unlocker.exe in una riga di comando per visualizzare le opzioni.

C'è anche un versione portatile di Unlocker disponibile in modo da poter raggruppare nella distribuzione senza forzare gli utenti finali di installare l'applicazione.

Se tutto questo non si può contattare l'autore di Unlocker, controlla questo dal suo readme.

  

Licensing

     

Se siete interessati a   ridistribuendo Unlocker, sia in   forma originale o modificata, o desiderio di   utilizzare Unlocker codice sorgente in un prodotto,   si prega di inviare e-mail a   ccollomb@yahoo.com con i dettagli.

...


4. Utilizzare Process Hacker Shared Biblioteche

Ho appena scoperto questo geniale strumento: Process Hacker che è scritto in 100% di codice C # (anche se non utilizza molte funzioni WinAPI tramite P / Invoke sotto il cofano).

La cosa migliore di questo: è open source (LGPL'd) e fornisce due librerie che gli sviluppatori possono fare riferimento nelle loro soluzioni: ProcessHacker.Common processoHacker.Native.

Ho scaricato la fonte e solo una parola di avvertimento è una abbastanza grande soluzione, può prendere un po 'di tempo per capire esattamente che cosa / come usarlo.

Esso utilizza le funzioni API non documentate (ntdll.dl) ho parlato in opzione 2 e può fare tutto Unlocker può e molto altro ancora.

Altri suggerimenti

Non sono sicuro se questo funziona per gli oggetti ActiveX, ma lo fa in via definitiva per assembly .NET. Io lo uso per unit testing in cui le DLL devono essere sovrascritti senza intoppi. Il meccanismo utilizzato è ombra copia .

Chiusura gestisce dall'esterno la domanda non sembra davvero una scelta molto sicuro.

Non è la soluzione forse un'idea o la direzione ...

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top