2

Visual Studio セットアップ プロジェクトを介して展開されているアプリケーションがありますが、ユーザーから特定のデータを収集するために、いくつかのカスタム Windows フォームを作成する必要がありました。これらのフォームは、アプリケーション ファイルが Setup Project (IE the MSI) によってデプロイされた直後に、アプリケーションの Installer クラスの Install() メソッドで表示されます。問題は、フォームが表示されたときに、画面の一番上のフォームではなく、セットアップ プロジェクトのウィンドウの下に表示されることです。次に、ユーザーが気付いた場合でも、タスクバーのアイコンをクリックしてフォームを手動で表示する必要があります。

4

4 に答える 4

4

私がしなければならなかったことは、プロセスのリストから Setup プロジェクトのウィンドウを選択し、それをカスタム フォームの所有者として表示するように設定することだけでした。使用した手順の内訳は次のとおりです。

  1. 「msiexec」という名前のプロセスのリストを調べて、Setup .msi のウィンドウを表示しているプロセスのハンドルを取得します。これは MainWindowTitle (ウィンドウのタイトル) で識別できます。
  2. これで、このプロセスのハンドル (MainWindowHandle) を取得できましたが、それをどのように使用するのでしょうか? IWin32Window を受け取るパラメーターを介して ShowDialog を呼び出すときに、フォームの所有者を指定できます。問題は、IWin32Window ではウィンドウのハンドルを設定できないことです。これは、IWin32Window を拡張するラッパー クラスを使用することで回避できます。
  3. 最後に、CustomForm.ShowDialog(new WindowWrapper(process.MainWindowHandle), message など) のようなものを使用して、ShowDialog() を呼び出すときにフォームの所有者を設定するだけです。

私自身、Setup Project のウィンドウを WindowWrapper として返すメソッドを作成し、Installer クラスの各メソッド (Install、Commit、Uninstall、Rollback) でそれを使用して、作成中のすべてのフォームとメッセージボックスの所有者を設定しました。

また、カスタム フォームの子フォームまたはメッセージ ボックスの所有者を変更しないでください (おそらく "this" を除く)。そうしないと、Setup プロジェクトのウィンドウの上に表示されますが、カスタム フォームの下に表示されます。

    public override void Install(System.Collections.IDictionary stateSaver)
    {
        base.Install(stateSaver);
        try
        {
            ExecuteSqlScript();
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }

    private void ExecuteSqlScript()
    {
        IntPtr hwnd = IntPtr.Zero;
        WindowWrapper wrapper = null;
        Process[] procs = Process.GetProcessesByName("msiexec");
        if (null != procs && procs.Length > 0)
            hwnd = procs[0].MainWindowHandle;
        wrapper = new WindowWrapper(hwnd);
        //Set the windows forms owner to setup project so it can be focused and
        //set infront
        frmInstance objInstance = new frmInstance();
        if (null != wrapper)
            objInstance.ShowDialog(wrapper);
        else
            objInstance.ShowDialog();
    }

    public class WindowWrapper : System.Windows.Forms.IWin32Window
    {
        public WindowWrapper(IntPtr handle)
        {
            _hwnd = handle;
        }

        public IntPtr Handle
        {
            get { return _hwnd; }
        }

        private IntPtr _hwnd;
    }
于 2012-04-09T13:00:14.763 に答える
1

リストの最初の要素を選択することはお勧めできません。以下のコードはテスト済みで機能しています。

internal static IntPtr InstallerWindow()
{
  IntPtr hwnd = IntPtr.Zero;

  foreach (var proc in Process.GetProcessesByName("msiexec"))
  {
    if (proc.MainWindowHandle == IntPtr.Zero)
      continue;

    if (string.IsNullOrEmpty(proc.MainWindowTitle))
      continue;

    hwnd = proc.MainWindowHandle;
    break;

  }

  return hwnd;
}
于 2014-02-06T17:42:41.087 に答える
0

次のコードを使用します。このコードは、フォームにフォーカスを当てます

    [DllImport("user32.dll", SetLastError = true)]
    static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);

    // When you don't want the ProcessId, use this overload and pass IntPtr.Zero for the second parameter
    [DllImport("user32.dll")]
    static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId);

    [DllImport("kernel32.dll")]
    static extern uint GetCurrentThreadId();

    /// <summary>The GetForegroundWindow function returns a handle to the foreground window.</summary>
    [DllImport("user32.dll")]
    private static extern IntPtr GetForegroundWindow();

    [DllImport("user32.dll")]
    static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);

    [DllImport("user32.dll", SetLastError = true)]
    static extern bool BringWindowToTop(IntPtr hWnd);

    [DllImport("user32.dll", SetLastError = true)]
    static extern bool BringWindowToTop(HandleRef hWnd);

    [DllImport("user32.dll")]
    static extern bool ShowWindow(IntPtr hWnd, uint nCmdShow);  

       myform.Show();         
        uint foreThread = GetWindowThreadProcessId(GetForegroundWindow(), IntPtr.Zero);
        uint appThread = GetCurrentThreadId();
        const uint SW_SHOW = 5;
        if (foreThread != appThread)
        {
            AttachThreadInput(foreThread, appThread, true);
            BringWindowToTop(myform.Handle);
            ShowWindow(objFrmViewer.Handle, SW_SHOW);
            AttachThreadInput(foreThread, appThread, false);
        }
        else
        {
            BringWindowToTop(myform.Handle);
            ShowWindow(myform.Handle, SW_SHOW);
        }
        myform.Activate();

    }
于 2012-04-09T08:04:20.537 に答える
0

MSDN では、フォームを前面に移動し、前面に保持する方法について説明しています。

http://msdn.microsoft.com/en-us/library/3saxwsad.aspx

于 2012-04-09T08:06:09.393 に答える