2012-04-26 3 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

Вам необходимо «RedrawWindow» с 'RDW_FRAMECHANGED', чтобы перерисовать с новыми границами. Разве вы не должны использовать свойство 'FormBorderStyle', а не стирать стили? –

+0

Спасибо, но я не получаю границы с этой функцией. Я использовал: «RedrawWindowFlags.Invalidate And 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(); 
    } 

заметить Также я использую GetWindowLongPtr, SetWindowLongPtr и SetWindowPosPtr с IntPtr в качестве аргументов вместо GetWindowLong, SetWindowLong и SetWindowPos Int/UINT. Это связано с совместимостью 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 global и определить его из определения метода 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 является нелокальной переменным, и ссылаться на поле MenuHandle , которая определяется из RemoveBorders метод. IntelliSense все еще распознает его как поле , а не будет предупреждает вас о неопределенной ошибке.

Если MenuHandle является нестатический, то вы можете также добавить this. Ключевое слово после удаления IntPtr перед тем MenuHandle (Другими словами, вы можете заменить IntPtr с this.), чтобы запомнить себя, что MenuHandle является нелокальная переменная больше, так что сборщик мусора не удалить его всякий раз, когда RemoveBorders заканчивает работа.

Когда вы запустите свою программу, MenuHandle будет присвоено значение IntPtr.Zero в качестве значения по умолчанию. Когда вы вызываете RemoveBorders для сначала, значение MenuHandle будет установлено на возвращаемое значение функции GetMenu в if (Remove).

Когда удаленные панели заканчиваются для , сначала раз, MenuHandle не удаляется и сохраняет предыдущее состояние меню окна, прежде чем все его элементы будут удалены.

Так что, когда вы звоните RemoveBorders для второго времени для того, чтобы восстановить меню, исполнитель достигнет if (Remove) код и перейти непосредственно к else кода, так как удалить = ложь, и там вы вызываете функцию SetMenu, когда вы даете ему previous Состояние меню окна с сначала звоните в RemoveBorders. Таким образом, вы сможете, наконец, восстановить меню окна.

Я все еще не понимаю, почему вам нужно дважды удалять границы, когда панель меню все еще существует. Я хочу помочь вам решить эту проблему, но понятия не имею. В этом случае ваш код верен. Извините, но я надеюсь, что другие люди могут решить эту проблему для вас и дать вам решение для этого.

0

Я решил проблему о следующем пункте:

Я не могу восстановить в меню для

О вашей проблеме в другой точке

Мне нужно удалить границы дважды, первый раз, когда строка меню все еще существует.

У меня нет решения, что извинит, но я надеюсь, что другие люди помогут с этим.

Удалите весь код, который определяет ваш метод RemoveBorders, который вы отправили в своем вопросе, и затем выберите весь следующий код, который я опубликовал ниже (используйте Ctrl + A, если он работает), скопируйте его (щелкните правой кнопкой мыши щелкните => выберите «Копировать» или просто нажмите Ctrl + C быстрее), а затем вставьте его (щелкните правой кнопкой мыши => выберите «Вставить» или просто нажмите Ctrl + V быстрее). Убедитесь, что позиция курсора в редакторе кода находится в правильном месте, где старый код, который определил ваш метод RemoveBorder, был перед вставкой нового кода. Мой новый код, который переопределяет 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; 
} 

Изменения, которые были сделаны из старой версии моей новой версии методы RemoveBorders:

Прежде всего, возвращаемое значение методы изменяется от void к IntPtr , так что строки кода

return MenuHandle;

был добавлен ниже последнего вызова функции SetWindowLong. Цель этого изменения состояла в том, чтобы программа RemoveBorders вернула дескриптор меню (как тип IntPtr в C#), который принадлежал окну, до того, как его границы были удалены из него. Это важно, потому что в следующий раз, когда вы снова вспомните RemoveBorders, чтобы восстановить границу окна, вам нужно вернуть дескриптор своего меню. Вот почему второй аргумент RemoveBorders (bool remove) был изменен на IntPtr MenuHandle, чтобы вы могли вернуть меню окна и восстановить его границы. В результате мне пришлось удалить перед MenuHandle в первой строке кода, чтобы объявить, что MenuHandle - это , а не локальная переменная, но теперь это аргумент. Установите этот аргумент в IntPtr.Zero (что означает NULL в C++) всякий раз, когда вы хотите удалить границы окна. Из-за того, что удалить аргумент был заменен, и поэтому не существует в моей новой версии больше, код строка if (remove) была изменена на

if (MenuHandle == IntPtr.Zero)

Он проверяет, что вы не дали ручки меню на окна, то вы хотите удалить его границы. Действие выполняется внутри оператора if. Если вы вернете меню окна, то MenuHandle не будет NULL (т. Е.IntPtr.Zero), а затем код вводится в оператор else для восстановления. Последнее значение очень важно. Изменение заключалось в том, чтобы переместить первую строку кода, где был удален IntPtr, и когда вы вызываете функцию GetMenu внутри блока оператора if, перед вызовом функции GetMenuItemCount, потому что нам нужно получить меню окна и сохранить его , прежде чем его границы будут удалены, а не всегда. Без этого изменения вы не сможете восстановить границы окна, потому что первая строка кода «отбросит» меню окна, которое вы вернули, потому что вы вызываете функцию GetMenu, когда в окне нет меню, поэтому возвращаемое значение этой функции будет NULL (IntPtr.Zero в C#), поэтому в блоке else вы устанавливаете меню окна на IntPtr.Zero (что означает NULL на C++). С этим изменением новый метод RemoveBorders должен работать правильно и позволить вам восстанавливать границы окна.

Отныне вы должны использовать мою новую версию для RemoveBorders вместо старой версии, чтобы иметь возможность восстанавливать границы окна. Надеюсь, вы поняли мою идею в этом изменении. Инструкции просты: определите новую переменную типа IntPtr, и всякий раз, когда вы вызываете RemoveBorders, чтобы удалить границу окна, назначьте эту переменную возвращаемому значению метода, чтобы сохранить и сохранить меню окна, после того как его границы были удалены , Позже вы снова вспомните RemoveBorders, но теперь для восстановления границ окна, поэтому вы устанавливаете второй аргумент переменной, которая хранит меню окна, то есть возвращаемое значение предыдущего вызова метода RemoveBorders. Надеюсь, что это поможет!

Смежные вопросы