简体   繁体   中英

C# application dragdrop doesn't work when called in memory

I have made an application, called MemoryLauncher, that pulls the binary of another application's executable into memory and runs it. The purpose of MemoryLauncher is to allow me to overwrite the.EXEs of the other programs when an update is available without having to worry about another user running and locking the program. This works really well for me except for one thing: drag/drop. I have created a device manager program that MemoryLauncher will execute and this program requires the drag/drop feature but it seems to be disabled when the.EXE is called into memory. If I launch the device manager normally, then the drag/drop feature works fine. I thought that maybe this was due to elevated priviledges so I tried adding the following code to the device mananager and MemoryLauncher with no luck:

ChangeWindowMessageFilterEx(this.Handle, WM_DROPFILES, MSGFLT_ADD, IntPtr.Zero);
ChangeWindowMessageFilterEx(this.Handle, WM_COPYDATA, MSGFLT_ADD, IntPtr.Zero);
ChangeWindowMessageFilterEx(this.Handle, WM_COPYGLOBALDATA, MSGFLT_ADD, IntPtr.Zero);

Here's the code for the MemoryLauncher program that actually takes the binary of the other application and runs it:

static class Program
    {
        private static string[] mainArgs;
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main(string[] args)
        {
            mainArgs = args;

            if (mainArgs.Length == 0)
                MessageBox.Show("Please run from shortcut or command line.", "MemoryLauncher.EXE");
            else
            {
                try
                {
                    if (mainArgs[0].Substring(mainArgs[0].Length - 1) != "\\")
                        mainArgs[0] += "\\";

                    byte[] bin = makeBinary(Path.Combine(Path.Combine(Directory.GetCurrentDirectory(), mainArgs[0]), mainArgs[1]));

                    AppDomain ad = AppDomain.CurrentDomain;
                    ad.AssemblyResolve += new ResolveEventHandler(ad_AssemblyResolve);

                    Assembly assembly = Assembly.Load(bin);
                    MethodInfo method = assembly.EntryPoint;

                    if (method != null)
                    {
                        Object obj = assembly.CreateInstance(method.Name);

                        String[] argsToPass = null;
                        if (mainArgs.Length > 2 && mainArgs[2] == "/a")
                        {
                            argsToPass = new string[mainArgs.Length - 1];
                            for (int i = 3; i < mainArgs.Length; i++)
                                argsToPass[i - 3] = mainArgs[i];
                        }

                        if (argsToPass != null)
                            method.Invoke(obj, new object[] { argsToPass });
                        else
                            method.Invoke(obj, null);
                    }
                }
                catch (Exception e) { MessageBox.Show("ERROR: " + e.Message, "MemoryLauncher.EXE"); }
            }
        }

        static Assembly ad_AssemblyResolve(object sender, ResolveEventArgs resolveArgs)
        {
            //Load the assembly from the specified path.
            AssemblyName assemblyName = new AssemblyName(resolveArgs.Name);

            string folder = mainArgs[0];

            byte[] bin = makeBinary(Path.Combine(Path.Combine(Directory.GetCurrentDirectory(), folder), assemblyName.Name + ".dll"));
            return Assembly.Load(bin);
        }

        static byte[] makeBinary(string pathName)
        {
            FileStream fs = new FileStream(pathName, FileMode.Open);
            BinaryReader br = new BinaryReader(fs);
            byte[] bin = br.ReadBytes(Convert.ToInt32(fs.Length));
            fs.Close();
            br.Close();

            return bin;
        }
    }

I don't know the precise answer to your question, but that isn't the best way to run a program without locking it.
You should use.Net's ShadowCopy feature, which is specifically designed to do this.
I wrote the following launcher using it:

using System;
using System.IO;
using System.Reflection;
using System.Security;
using System.Security.Permissions;
using System.Collections;
using System.Security.Policy;

[assembly: AssemblyVersion("1.1.0.0")]
namespace ShadowLauncher {
    static class Program {
        [STAThread]
        static int Main(string[] args) {
            if (args.Length == 0 || !File.Exists(args[0]))
                return 1;

            var assembly = args[0];
            var realArgs = new string[args.Length - 1];
            if (realArgs.Length > 0)
                Array.Copy(args, 1, realArgs, 0, realArgs.Length);

            var permissions = new PermissionSet(PermissionState.Unrestricted);

            AppDomain.CreateDomain(Path.GetFileNameWithoutExtension(assembly),
                AppDomain.CurrentDomain.Evidence,
                new AppDomainSetup {
                    ShadowCopyFiles = "true",
                    ConfigurationFile = assembly + ".config",
                    ApplicationBase = Path.GetDirectoryName(Path.GetFullPath(assembly))
                },
                permissions
            ).ExecuteAssembly(assembly, AppDomain.CurrentDomain.Evidence, realArgs);
            return 0;
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM