2012-04-26 26 views
3

C#で別のプロセスのウィンドウ枠を削除したい。 RemoveMenuを使用して枠線を削除しました。それはほとんど動作しますが、私は左の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を保存して後で元に戻そうとしましたが、うまくいきません。

+1

新しい枠線で再描画するには、 'RDW_FRAMECHANGED'で' RedrawWindow'する必要があります。スタイルを叩く代わりに 'FormBorderStyle'プロパティを使用してはいけませんか? –

+0

ありがとうございますが、私はその機能を使って罫線を戻すことはありません。私は使用しました: "RedrawWindowFlags.InvalidateとRedrawWindowFlags.Frame" – Laurence

+1

おっと、メモリが私に失敗しました。 'SWP_FRAMECHANGED'だったはずです。しかし、なぜあなたは別のプロセスに属しているウィンドウにうんざりしていますか?それは一種の失礼です。 –

答えて

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の引数としてのIntPtrでGetWindowLongPtr、SetWindowLongPtrとSetWindowPosPtrを使用気づきます。これは、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)); 
     } 
    } 

ホープこのことができますインポートを行う方法です。

1
  • 私はあなたのMenuHandleがローカル変数であることをこれは、メニューの

を復元することはできません。

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

あなたが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はまだそれをフィールドと認識し、で未定義エラーを警告しません。

MenuHandleがない静的であれば、あなたもthisを追加することができます。 MenuHandleはもうないローカル変数なので、RemoveBordersが終了するたびにガベージコレクタはそれを削除しないことを自分自身を記憶するMenuHandle前のIntPtrを除去した後、キーワード(言い換えれば、あなたはthis.IntPtrを置き換えることができます)、ジョブ。

プログラムを起動すると、MenuHandleがデフォルト値としてIntPtr.Zeroに割り当てられます。 最初に時間のRemoveBordersを呼び出すと、MenuHandleの値はif (Remove)のGetMenu関数の戻り値に設定されます。

最初にのときにRemoveBordersが終了すると、MenuHandleは削除されず、アイテムのすべてが削除される前に、ウィンドウのメニューの以前の状態が保存されます。そこにあなたがSetMenu関数を呼び出す削除=偽、およびので

、メニューを復元するために、時間RemoveBordersを呼び出すときに、executorがif (Remove)コードに達し、elseコードにすぐにジャンプし、ときあなたはを前にウィンドウのメニューの状態最初に RemoveBordersを呼び出します。 この方法で、最終的にウィンドウのメニューを復元することができます。

なぜ、メニューバーがまだ最初に残っているにもかかわらず、境界線を2度削除する必要があるのはわかりません。 私はあなたにもこの問題を解決するのを手伝いたいと思っていますが、分かりません。 あなたのコードはこの場合正しいです。申し訳ありませんが、私は他の人々があなたのためにこの問題を解決し、あなたにもこれの解決策を与えることを願っています。

0

私は、次の点についてのあなたの問題を解決した:私は削除する必要がある他の点では、あなたの問題について

をメニューの

を復元することはできません

最初のメニューバーはまだ が存在します。

私は申し訳ありませんのためにソリューションを持っていないが、私は他の人がそれに役立つことを願っています。

あなたの質問に投稿し、の下にの下に投稿したすべてのコードを選択してRemoveBordersメソッドを定義するすべてのコードを削除します(Ctrl + Aを使用します)をクリックして貼り付けてください(右クリック→「貼り付け」またはをコードに貼り付けて貼り付けてください)。新しいコードを貼り付ける前に、コードエディターでのカーソルの位置がRemoveBorderメソッドを定義した古いコードの正しい場所にあることを確認します。 RemoveBordersを再定義私の新しいコードは次のとおりです。RemoveBorders方法の私の新しいバージョンに古いバージョンから作られた

public IntPtr RemoveBorders(IntPtr WindowHandle, IntPtr MenuHandle) 
{ 
    if (MenuHandle == IntPtr.Zero) 
    { 
     MenuHandle = GetMenu(WindowHandle); 
     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)); 
    return MenuHandle; 
} 

変更:すべての

まず、メソッドの戻り値はIntPtrvoidから変更しました、そのコード行

return MenuHandle;

SetWindowLong機能へのあなたの最後の呼び出しの下に追加されました。この変更の目的は、境界線が削除される前に、ウィンドウに属していたメニューのハンドル(C#のIntPtr型として)を返すようにRemoveBordersをプログラムすることでした。これは重要です。次に、ウィンドウの境界線を復元するためにRemoveBordersを再度呼び出すときに、そのメニューのハンドルを戻す必要があるためです。これは、RemoveBorders(bool remove)の2番目の引数がIntPtr MenuHandleに変更されたため、ウィンドウのメニューを戻してその枠線を復元できる理由です。その結果、最初のコード行でMenuHandleの前にIntPtrを削除して、MenuHandleがではなく、というローカル変数を宣言する必要がありましたが、これは今や引数です。 の場合は、この引数をIntPtr.Zero(つまり、C++ではNULLを意味します)に設定します。ウィンドウの境界線を削除します。削除引数はもう私の新しいバージョンには存在しないので、交換したことで、コード行if (remove)

if (MenuHandle == IntPtr.Zero)

に変更されたため、それはあなたがメニューのいずれかのハンドルを与えていないことを確認しますその枠線を削除したいと考えています。アクションはifステートメント内で実行されます。ウィンドウのメニューを返すと、MenuHandleはNULL(つまり、IntPtr.Zero)、その後、コードは、復元を行うためにelseステートメントに持ち込まれます。最後非常に重要変更は、GetMenuItemCount関数を呼び出す前に、IntPtrが削除された最初のコード行と、GetMenu関数を呼び出す場所をif文ブロック内で移動することでした。ウィンドウのメニューを取得して保持する必要があるからですその境界線が削除される前に、が必ずしもであるとは限りません。この変更がなければ、ウィンドウの境界線を元に戻すことはできません。ウィンドウのメニューが表示されていないときにGetMenu関数を呼び出すため、コードの最初の行が返されたウィンドウのメニューを "破棄"します。この関数の戻り値はNULL(C#のIntPtr.Zero)になります。したがって、elseブロックでは、ウィンドウのメニューをIntPtr.Zeroに設定します(これはC++ではNULLを意味します)。この変更により、新しいRemoveBordersメソッドが正しく機能し、ウィンドウの境界線を復元できるようになります。

これからは、ウィンドウの罫線を復元できるように、古いバージョンではなくRemoveBordersに新しいバージョンを使用する必要があります。私はあなたがこの変化の中で私の考えを理解したことを願っています指示は単純です:IntPtrタイプの新しい変数を定義し、ウィンドウの境界線を削除するためにRemoveBordersを呼び出すたびに、その変数をメソッドの戻り値に代入すると、その境界線が削除された後にウィンドウのメニューを保持して保存します。後でRemoveBordersを再度呼び出しますが、ウィンドウの境界線を復元するために、ウィンドウのメニューを保持する変数、つまりRemoveBordersメソッドへの前回の呼び出しの戻り値を保持する変数に2番目の引数を設定します。あなたを助けることを願っています!

関連する問題