2013-08-07 3 views
3

У нас есть приложение wpf, которое должно быть «пилотировано» устаревшим приложением win32 winform. (Мы не являемся владельцем кода;))Wpf и Hwnd уникальное имя

Унаследованное приложение должно пилотировать наше приложение (сводить к минимуму, выводить на передний план, закрывать и т. Д.) С помощью имени windowsclass, которое мы должны предоставить в качестве параметра конфигурации, записанного в ini-файл.

Проблема заключается в том, что мы не можем заставить ее работать с wpf, поскольку, если мы вставим имя класса Spy ++, дадим нам, ничего не произойдет. Дело в том, что Spi ++ возвращает что-то вроде этого

HwndWrapper[MyWpfProgram.exe;;16978ce2-3b8d-4c46-81ee-e1c6d6de4e6d] 

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

Есть ли способ решить эту проблему?

спасибо.

ответ

0

Для оконных дескрипторов, названий и имен классов Spy ++ использует довольно простые API Windows.

FindWindowEx http://msdn.microsoft.com/en-us/library/windows/desktop/ms633500%28v=vs.85%29.aspx

EnumWindows http://msdn.microsoft.com/en-us/library/windows/desktop/ms633497%28v=vs.85%29.aspx

GetClassName http://msdn.microsoft.com/en-us/library/windows/desktop/ms633582%28v=vs.85%29.aspx

Вы можете создать программу "загрузчик", который ...

  • Начало МОФ приложение
  • Используйте выше API, чтобы получить правильные имена классов и окна обрабатывает
  • Отредактируйте унаследованного INI
  • Начало наследие приложение
+0

Ваше решение, если хорошо, но для наших целей это не так полезно, это наследие приложение, которое запускает наше приложение, поэтому имя класса должно быть уникальным –

+0

@ Stefano.net - Когда вы используете инструмент «Найти окно» в Spy ++, что является результатом работы класса: ??? это именно тот пример, который вы показываете в своем вопросе? http://msdn.microsoft.com/en-us/library/dd460750.aspx –

+0

да точно. Как я уже сказал в вопросе, изменения guid при каждом исполнении –

1

Использование HwndSource.

Вы можете использовать родной Windows API, требует, чтобы создать окно с ожидаемым именем класса, а затем использовать HwndSource, чтобы добавить содержимое WPF к нему:

var source = HwndSource.FromHwnd(nativeWindowHandle); 
source.RootVisual = mainGrid; 

Если вам нужно использовать окно WPF, я думаю, вы могли бы все еще решайте это с помощью окна «прокси», но это будет не так:

  • Попросите приложение WPF создать собственное окно message-only.
  • Используйте HwndSource.AddHook для обработки сообщений типа WM_CLOSE, WM_SIZE в собственном окне и передайте их в «реальное» окно WPF.
+0

Это точно, что мы сделали. См. Мой ответ –

2

Невозможно делать то, что я просил. Но мы нашли прогулку. «Просто» встраивание окон xaml в форму Windows.

Эти шаги мы следовали:

1 - Добавление формы Windows в проект.

2 - Удалите app.xaml и сделайте новую форму точкой входа приложения.

3 - Так как нам нужно HWND в main.xaml мы добавили эту опору для своего кода за

public IntPtr Hwnd 
    { 
     get { return new WindowInteropHelper(this).Handle; } 
    } 

4 - то из конструктора формы мы создаем экземпляр окна МОФ класса

private Main app; 
    public ContainerForm() 
    { 
     InitializeComponent(); 

     app = new Main(); 
     ElementHost.EnableModelessKeyboardInterop(app); 
    } 

мы нуждались в

ElementHost.EnableModelessKeyboardInterop(app); 

, так как мы хотим, чтобы все ввод с клавиатуры, чтобы перейти от окна образуют окно xaml

5 - теперь мы хотим связать окно xpf с winform. Для этого нам нужно использовать Windows Api, и мы делаем это в событии OnShow формы (причина, объясняемая позже).

[DllImport("user32.dll", SetLastError = true)] 
    private static extern long SetFocus(IntPtr hWnd); 

    [DllImport("user32.dll", SetLastError = true)] 
    private static extern long SetParent(IntPtr hWndChild, IntPtr hWndNewParent); 


    [DllImport("user32.dll", SetLastError = true)] 
    private static extern bool MoveWindow(IntPtr hwnd, int x, int y, int cx, int cy, bool repaint); 

    [DllImport("user32.dll", EntryPoint = "SetWindowLongA", SetLastError = true)] 
    private static extern long SetWindowLong(IntPtr hwnd, int nIndex, long dwNewLong); 
    private const int GWL_STYLE = (-16); 
    private const int WS_VISIBLE = 0x10000000; 

    private void ContainerForm_Shown(object sender, EventArgs e) 
    { 
     app.Show(); 
     SetParent(app.Hwnd, this.Handle); 
     SetWindowLong(app.Hwnd, GWL_STYLE, WS_VISIBLE); 
     MoveWindow(app.Hwnd, 0, 0, this.Width, this.Height, true); 

     SetFocus(app.Hwnd); 
    } 

с

SetParent(app.Hwnd, this.Handle); 

ие сделать магию, то с

SetWindowLong(app.Hwnd, GWL_STYLE, WS_VISIBLE); 

убирает Al хром из окна МОФА (есть граница, даже если окно определяются без полей , не спрашивайте меня почему)

затем мы создаем окно wpf, заполняем всю клиентскую область winform

MoveWindow(app.Hwnd, 0, 0, this.Width, this.Height, true); 

, а затем мы ориентируемся окно МОФ

SetFocus(app.Hwnd); 

, что причина, почему мы делаем все, что в шоу-мероприятия. Поскольку, если мы сделаем это в конструкторе формы, окно wpf потеряет свой фокус, так как в winform главное окно получило фокус от операционной системы.

Мы не понимали, почему нам нужно было добавить другие вызовы api в этот момент, но если мы оставили их в конструкторе, трюк не сработал.

Во всяком случае, проблема решена;)