Pergunta

Quando um ActiveXObject está hospedado em um Windows Desktop / Sidebar Gadget, que ActiveXObject é uma espécie de cache eo arquivo DLL para ele está bloqueado (o que significa que não pode ser movido, excluído ou renomeado). O problema é este; quando o gadget é posteriormente fechada, a DLL ainda está bloqueado pelo Windows Sidebar e não pode ser removido. Isso faz com que um problema significativo em que uma nova versão do gadget não pode ser instalado por cima de uma versão anterior do gadget, ele falha durante o processo de excluí-lo sem quaisquer mensagens de erro.

Isto não é muito user-friendly, assim que eu estou procurando uma maneira de laços "separe" para o controle ActiveX de alguma forma durante o evento de descarregamento do gadget. Eu estou esperando que alguém pode me dizer se este é ou não possível e se for me dar algumas ideias sobre como implementá-lo.

FYI, Windows Sidebar Gadgets são realmente apenas janelas servidor do Internet Explorer, por isso é provavelmente seguro assumir IE exibe o mesmo comportamento.

EDIT: Unlocker parece fazer muito bonito o que eu preciso para fazer, então como eu posso conseguir a mesma coisa de programação em .NET?

Foi útil?

Solução

Ok este é um problema bastante complexo. Eu já vi esse comportamento antes, eu não estou familiarizado com o Windows Desktop / Sidebar Gadget como eu não usá-lo. No entanto eu consegui vir para cima com três possíveis métodos de ataque

1. Handle da TechNet

Esta ideia não foi minha, há um outro fio StackOverflow que recomenda este método. No entanto, eu sou cético quanto à possibilidade ou não este trabalho. Há uma diferença entre um bloqueio de arquivo (o que esta utilidade alças) e um bloqueio "biblioteca carregada", que é o que eu assumo é o problema que você está tendo com ActiveX.

Eu modifiquei o código de esse segmento pouco, não usam Process.Kill () para liberar o bloqueio, eu acho que é melhor usar Handle.exe para libertar o bloqueio.

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 Estilo

Não há um monte de informações sobre os internets sobre isso, e ao que parece há algumas chamadas de API sem documentos que são necessários para conseguir isso sem problemas.

I estes ++ exemplos c pode ajudar.

Infelizmente eu não poderia chegar a este trabalho perfeitamente. Testei este método usando um ActiveX carregado no MS Word. Eu, então, tentou desbloquear o ActiveX, não é muito estável e, muitas vezes causada palavra para acidente. Eu acho que eu não tenho as c ++ feridas de guerra necessários para decifrar os programas acima corretamente.

Junto com este exemplo de CreateRemoteThread em C # eu colocar este código juntos.

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 usar Unlocker

Esta é a minha melhor recomendação. Punho de TechNet não pode manipular carregado dll / ocx fechaduras (sob os testes). Win32 é confuso e em situação irregular.

Unlocker fornece acesso de linha de comando para que você possa chamá-lo exatamente da mesma forma que Handle.exe. Apenas wack a /? após unlocker.exe em um prompt de comando para ver os switches.

Há também um versão portátil do Unlocker disponível para que possa empacotá-lo em sua implantação sem forçar os usuários finais para instalar o aplicativo.

Se tudo mais falhar, você pode entrar em contato com o autor do Unlocker, confira este de seu readme.

Licenciamento

Se você está interessado em redistribuição Unlocker, quer em original ou modificada forma, ou desejo de usar o código fonte Unlocker em um produto, por favor envie e-mail para ccollomb@yahoo.com com detalhes.

...


4. Use Process Hacker bibliotecas compartilhadas

Eu só descobri esta ferramenta brilhante: Hacker processo que é escrito em 100% código C # (apesar de não usar uma grande quantidade de funções WinAPI via P / invocação sob o capô).

A melhor coisa sobre isso: é open source (LGPL'd) e fornece duas bibliotecas que os desenvolvedores podem fazer referência em suas soluções: Processo ProcessHacker.CommonHacker.Native.

Eu baixei a fonte e apenas uma palavra de aviso é um muito grande solução, poderá levar um pouco de tempo para descobrir exatamente o que / como usá-lo.

Ele usa as funções da API indocumentados (ntdll.dl) falei na opção 2 e pode fazer tudo o Unlocker pode e muito mais.

Outras dicas

Não tenho certeza se isso funciona para objetos ActiveX, mas ele definitivamente faz para conjuntos .NET. Eu uso ele para UnitTesting onde as DLLs tem que ser substituído sem problemas. O mecanismo utilizado é sombra copiar .

O encerramento de alças de fora um aplicativo não parece realmente uma opção muito segura.

Não é a solução talvez uma idéia ou direção ...

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top