3

C# で別のプロセスのウィンドウ境界を削除したい。RemoveMenu を使用して境界線を削除しました。ほとんど動作しますが、2 つの問題が残っています。

  • 最初にメニュー バーがまだ存在するときに、境界線を 2 回削除する必要があります。
  • メニューを元に戻せない

これは私がすでに書いたものです:

public void RemoveBorders(IntPtr WindowHandle, bool Remove)
    {
        IntPtr MenuHandle = GetMenu(WindowHandle);

        if (Remove)
        {
            int count = GetMenuItemCount(MenuHandle);
            for (int i = 0; i < count; i++)
                RemoveMenu(MenuHandle, 0, (0x40 | 0x10));
        }
        else
        {
            SetMenu(WindowHandle,MenuHandle);
        }

        int WindowStyle = GetWindowLong(WindowHandle, -16);

        //Redraw
        DrawMenuBar(WindowHandle);
        SetWindowLong(WindowHandle, -16, (WindowStyle & ~0x00080000));
        SetWindowLong(WindowHandle, -16, (WindowStyle & ~0x00800000 | 0x00400000));
    }

誰かが私が間違ったことを教えてもらえますか? MenuHandle を保存して後で復元しようとしましたが、うまくいきません。

4

3 に答える 3

1
  • メニューを元に戻せない

これは、MenuHandle がローカル変数であるためです。

メソッド RemoveBordersの最初の呼び出しが終了すると、ガベージ コレクターは MenuHandle を削除し、メモリを解放します。

2回に RemoveBorders を呼び出すと、MenuHandle が新しいローカル変数として再作成され、ウィンドウのメニューの現在の状態 (メニュー項目のないメニュー) に再割り当てされます。

結果として:

MenuHandle は、ウィンドウのメニューの以前の状態を保存しません。これが、ウィンドウのメニューを復元できない理由を説明しています。

私のアドバイスは、MenuHandle をグローバル変数にして、RemoveBorders メソッド定義から定義することです。

これをプライベート、保護、またはパブリック フィールドとして定義し、別のプロパティを定義することもできますが、これはオプションであり、必須ではありません。この属性の方が適している場合は、静的として定義することもできます。

MenuHandle の定義の例を次に示します。

private IntPtr MenuHandle;
//or
IntPtr MenuHandle; //Defined outside of RemoveBorders, which is defined below this line, to show that MenuHandle is not local variable.
public void RemoveBorders(IntPtr WindowHandle, bool Remove)
//or
protected IntPtr MenuHandle;
//or
public IntPtr MenuHandle
//or
private static IntPtr MenuHandle
//or
static IntPtr MenuHandle
//etc...

行を移動する必要があります。

IntPtr MenuHandle = GetMenu(WindowHandle);

中身:

if (Remove)

GetMenuItemCount 関数の呼び出しの前。

また、その行を変更し、少なくとも IntPtr を削除して、MenuHandle がローカル変数ではない ことを宣言し、RemoveBorders メソッドから定義された MenuHandleフィールドを参照する必要があります。IntelliSense はこれをfieldとして認識し、未定義のエラーを警告しません

MenuHandle がstaticでない 場合は、. MenuHandle の前の IntPtr キーワードを削除した後 (つまり、 に置き換えることができます ) 、MenuHandle がもはやローカル変数ではないことを覚えておいてください。したがって、ガベージ コレクターは、R​​emoveBorders がジョブを終了するたびにそれを削除しません。thisIntPtrthis.

IntPtr.Zeroプログラムを起動すると、デフォルト値としてMenuHandle が割り当てられます。初めてRemoveBorders を呼び出すと、MenuHandle の値は、if (Remove).

RemoveBorders が初めて終了するとき、MenuHandle は削除されず、すべてのアイテムが削除される前に、ウィンドウのメニューの以前の状態が保存されます。

したがって、メニューを復元するために2回目の RemoveBorders を呼び出すと、executor はコードに到達if (Remove)し、すぐにコードにジャンプします。これelseは、remove = false であるためです。RemoveBorders への最初の呼び出し以降のウィンドウのメニュー。このようにして、最終的にウィンドウのメニューを復元できます。

最初にメニュー バーがまだ存在するときに、境界線を 2 回削除する必要がある理由はまだわかりません。この問題も解決するのを手伝いたいのですが、わかりません。この場合、コードは正しいです。申し訳ありませんが、他の人がこの問題を解決し、解決策を提供してくれることを願っています。

于 2014-08-10T22:33:25.607 に答える
0

これを試して。これは私にとってはうまくいきます。この例では、境界線とメニューの削除はアプリ自体の内部で行われます。ただし、わずかな調整を行うだけで、外部ウィンドウで機能させることができます。

これらは、コードで宣言するいくつかの定数です



    const uint WS_BORDER = 0x00800000;
    const uint WS_DLGFRAME = 0x00400000;
    const uint WS_THICKFRAME = 0x00040000;
    const uint WS_CAPTION = WS_BORDER | WS_DLGFRAME;
    const uint WS_MINIMIZE = 0x20000000;
    const uint WS_MAXIMIZE = 0x01000000;
    const uint WS_SYSMENU = 0x00080000;
    const uint WS_VISIBLE = 0x10000000;
    const int GWL_STYLE = -16;

ウィンドウ枠の場合



Point originallocation = this.Location;
Size originalsize = this.Size;

public void RemoveBorder(IntPtr windowHandle, bool removeBorder)
{

    uint currentstyle = (uint)GetWindowLongPtr(this.Handle, GWL_STYLE).ToInt64();
    uint[] styles = new uint[] { WS_CAPTION, WS_THICKFRAME, WS_MINIMIZE, WS_MAXIMIZE, WS_SYSMENU };

    foreach (uint style in styles)
    {

        if ((currentstyle & style) != 0)
        {

            if(removeBorder)
            {

                currentstyle &= ~style;
            }
            else
            {

                currentstyle |= style;
            }
        }
    }

    SetWindowLongPtr(windowHandle, GWL_STYLE, (IntPtr)(currentstyle));
    //this resizes the window to the client area and back. Also forces the window to redraw.
    if(removeBorder)
    {

        SetWindowPosPtr(this.Handle, (IntPtr)0, this.PointToScreen(this.ClientRectangle.Location).X, this.PointToScreen(this.ClientRectangle.Location).Y, this.ClientRectangle.Width, this.ClientRectangle.Height, 0);
    }
    else
    {

        SetWindowPosPtr(this.Handle, (IntPtr)0, originallocation.X, originallocation.Y, originalsize.Width, originalsize.Height, 0);
    }
}

メニューの場合、これを行うことができます。



    public void RemoveMenu(IntPtr menuHandle, bool removeMenu)
    {
        uint menustyle = (uint)GetWindowLongPtr(menuStrip1.Handle, GWL_STYLE).ToInt64();

        SetWindowLongPtr(menuStrip1.Handle, GWL_STYLE, (IntPtr)(menustyle^WS_VISIBLE));
        // forces the window to redraw (makes the menu visible or not)
        this.Refresh();
    }

また、GetWindowLong、SetWindowLong、および SetWindowPos int/uint の代わりに、GetWindowLongPtr、SetWindowLongPtr、および SetWindowPosPtr を引数として IntPtr と共に使用していることにも注意してください。これは、x86/x64 の互換性のためです。

GetWindowLongPtr をインポートする方法は次のとおりです。



    [DllImport("user32.dll", EntryPoint = "GetWindowLong")]
    public static extern int GetWindowLong(IntPtr hWnd, int nIndex);

    [DllImport("user32.dll", EntryPoint = "GetWindowLongPtr")]
    public static extern IntPtr GetWindowLong64(IntPtr hWnd, int nIndex);

    public static IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex)
    {

        if (IntPtr.Size == 8)
        {

            return GetWindowLong64(hWnd, nIndex);
        }
        else
        {

            return new IntPtr(GetWindowLong(hWnd, nIndex));
        }
    }

お役に立てれば。

于 2013-03-21T14:53:21.167 に答える