0

I've currently been given the task of hosting a bunch of old VB6 exes insdide WPF while the seemingly infinite task or refactoring is taking place.

Hosting the EXE wasn't too tricky at all but making the process seamless has.

Currently the flow is: 1) Create View 2) Inject VM 3) Start Process and fire EXE. 4) WaitForInputIdle 5) SetParent 6) SetWindowLong 7) SetWindowPos

The issue I am getting is that with this method as far as I am aware the process has to load naturally before it can have SetParent called on it. This means that there is a flicker of the application before it lays to rest in the WPF control.
I would like to find a way to get rids of this, is there a method to open the process purely in memory or hidden (I have UseShellExecute set to true and WindowStyle = ProcessWindowStyle.Minimized).

Possibly there is a different way to open the process entirely which I am unaware of.

ViewModel Constructor

 public ShellViewModel()
    {
        WindowWidth = 600;
        WindowHeight = 500;
        MainTitle = "Main Title";
        BreadCrumb = "NA";
        IsLoading = true;

        Task.Factory.StartNew(() =>
        {
            //Process p = OpenProcess(@"C:\\Windows\\System32\\notepad.exe");
            Process p = OpenProcess(@"C:\\Program Files\\WinRAR\\WinRar.exe");

            return p;

        }).ContinueWith(r =>
        {
            try
            {
                Process p = r.Result;

                _handler = p.MainWindowHandle;
                _host.Child = _panel;
                Content = _host;

                int dwStyle = GetWindowLong(_handler, GWL_STYLE);
                SetParent(_handler, _panel.Handle);
                SetWindowLong(_handler, GWL_STYLE, new IntPtr(dwStyle & ~WS_CAPTION & ~WS_THICKFRAME));
                SetWindowPos(_handler, IntPtr.Zero, 0, 0, (int) Math.Round(WindowWidth), (int) Math.Round(WindowHeight) - 106, SWP_FRAMECHANGED);

                BreadCrumb += " Host: " + p.Id.ToString(CultureInfo.InvariantCulture);

                IsLoading = false;
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message);
            }

        }, UiTaskSchedulerHelper.Instance.UiTaskScheduler);
    }

Opening the process

private Process OpenProcess(string path)
    {

        Process p = null;
        lock (locked)
        {
            ProcessStartInfo psi = new ProcessStartInfo();
            psi.FileName = path;
            psi.UseShellExecute = true;
            psi.WindowStyle = ProcessWindowStyle.Minimized;
            p = Process.Start(psi);
            BreadCrumb += " OpenProcess: " + p.Id;

            p.EnableRaisingEvents = true;
            p.WaitForInputIdle();

        }
        return p;
    }

Uploaded the sample to github, feel free to update it.

https://github.com/OliDow/FormHostPoc/tree/master/FormHostPoc

Cœur
  • 37,241
  • 25
  • 195
  • 267
Oli
  • 428
  • 1
  • 5
  • 20
  • Perhaps `psi.WindowStyle=ProcessWindowStyle.Hidden`, and later restore the windowStyle, once the `SetParent` is done. – Erti-Chris Eelmaa Jan 02 '15 at 14:45
  • @ChrisEelmaa I had tried exchanging Minimised for hidden and it appeared to have little to any effect on the flicker. Do you know of any examples that would explain it? – Oli Jan 02 '15 at 15:04
  • does the flicker happen with any process? You could combinethese too: `(ProcessWindowStyle.Minimized|ProcessWindowStyle.Hidden)` – Erti-Chris Eelmaa Jan 02 '15 at 15:12

1 Answers1

0

So a day of pair programing and we got it loading as intended. The repo works correctly. We also had to set the loading VB6 Apps to start minimised in a config file.

Oli
  • 428
  • 1
  • 5
  • 20