2016-08-11 39 views
8

Próbuję osadzić osk w oknie wpf lub kontroli użytkownika i znalazłem poniższy kod i działa on dla notatnika, ale dla tabtip.exe, to znaczy, że nie ma interfejsu graficznego?Jak osadzić plik tabtip.exe w oknach

WaitForInputIdle nieudane. Może to być spowodowane tym, że proces nie ma interfejsu graficznego.

Próbowałem pozwalając mu spać na chwilę zamiast wywoływania metody waitForInputIdle ale rzuca kolejny wyjątek:

Process odszedł, więc żądana informacja nie jest dostępna.

Ale w moim menedżerze zadań nadal mogę zobaczyć działanie TabTip.exe.

namespace WpfApplication1 
{ 
    /// <summary> 
    /// Interaction logic for MainWindow.xaml 
    /// </summary> 
    public partial class MainWindow : Window 
    { 
     private System.Windows.Forms.Panel _panel; 
     private Process _process; 

     public MainWindow() 
     { 
      InitializeComponent(); 
      _panel = new System.Windows.Forms.Panel(); 
      windowsFormsHost1.Child = _panel; 
     } 

     [DllImport("user32.dll")] 
     private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong); 

     [DllImport("user32.dll", SetLastError = true)] 
     private static extern int GetWindowLong(IntPtr hWnd, int nIndex); 

     [DllImport("user32")] 
     private static extern IntPtr SetParent(IntPtr hWnd, IntPtr hWndParent); 

     [DllImport("user32")] 
     private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, int uFlags); 

     private const int SWP_NOZORDER = 0x0004; 
     private const int SWP_NOACTIVATE = 0x0010; 
     private const int GWL_STYLE = -16; 
     private const int WS_CAPTION = 0x00C00000; 
     private const int WS_THICKFRAME = 0x00040000; 


     protected override void OnClosing(System.ComponentModel.CancelEventArgs e) 
     { 
      base.OnClosing(e); 
      if (_process != null) 
      { 
       _process.Refresh(); 
       _process.Close(); 
      } 
     } 

     private void ResizeEmbeddedApp() 
     { 
      if (_process == null) 
       return; 

      SetWindowPos(_process.MainWindowHandle, IntPtr.Zero, 0, 0, (int)_panel.ClientSize.Width, (int)_panel.ClientSize.Height, SWP_NOZORDER | SWP_NOACTIVATE); 
     } 

     protected override Size MeasureOverride(Size availableSize) 
     { 
      Size size = base.MeasureOverride(availableSize); 
      ResizeEmbeddedApp(); 
      return size; 
     } 

     private void button1_Click_1(object sender, RoutedEventArgs e) 
     { 
      button1.Visibility = Visibility.Hidden; 
      ProcessStartInfo psi = new ProcessStartInfo("C:\\Program Files\\Common Files\\microsoft shared\\ink\\TabTip.exe"); 
      _process = Process.Start(psi); 

      Thread.Sleep(500); 
      //_process.WaitForInputIdle(); 

      SetParent(_process.MainWindowHandle, _panel.Handle); 

      // remove control box 
      int style = GetWindowLong(_process.MainWindowHandle, GWL_STYLE); 
      style = style & ~WS_CAPTION & ~WS_THICKFRAME; 
      SetWindowLong(_process.MainWindowHandle, GWL_STYLE, style); 

      // resize embedded application & refresh 
      ResizeEmbeddedApp(); 
     } 

    } 
} 

Edit: Zainspirowany komentarzem Rene, starałem się uzyskać ptr jak poniżej okna i używane spy ++, aby upewnić się, że adres, który FindWindow daje skierowany do właściwego okna, ale to nadal nie rusza:

IntPtr KeyboardWnd = FindWindow("IPTip_Main_Window", null); 


int style = GetWindowLong(KeyboardWnd, GWL_STYLE); 
style = style & ~WS_CAPTION & ~WS_THICKFRAME; 
SetWindowLong(KeyboardWnd, GWL_STYLE, style); 
SetWindowPos(KeyboardWnd, IntPtr.Zero, 0, 0, (int)_panel.ClientSize.Width, (int)_panel.ClientSize.Height, SWP_NOZORDER | SWP_NOACTIVATE); 

Edycja 2: Moja pierwsza myśl polegała na tym, że nie można zmienić rozmiaru końcówki tabulatora, ale zauważyłem zachowanie, gdy próbuję przesunąć okno na dwa różne ekrany, zmieni się rozmiar, dopasowując go do rozmiaru ekranu, więc jestem pewien, że musi istnieć sposób zmiany rozmiaru, więc zacząłem szpiegować ++ (x64), aby sprawdzić:

window log

Edit 3: po majstrować abit z User32 API i żadnego postępu, próbowałem użyć skanera pamięci do skanowania X i Y położenia tabtip i zmienić go, jednak nie jest to orzeźwiający aż repaint jest wyzwalany, zastanawiam się, czy wykonam tę ścieżkę.

+1

Domyślam się, że uruchamiana instancja jest natychmiast zamykana. [Te odpowiedzi] (http://stackoverflow.com/questions/17090325/show-hiding-the-windows-8-on-screen-keyboard-from-wpf) sugerują, że musisz szukać okna, które niekoniecznie główne okno instancji procesu, którą uruchomiłeś. – rene

+0

może to pomóc http://geekswithblogs.net/TechTwaddle/archive/2009/10/16/how-to-embed-an-exe-inside-another-exe-as-a.aspx – Mangrio

+0

@QadeerMangrio Jestem patrząc na graficznie osadzony tabtip w innym oknie, z tego co rozumiem, blog mówi o tym, jak osadzić w pamięci. –

Odpowiedz

1

Czy możesz spróbować uruchomić swój kod obsługi w wątku STA? Miałem podobny problem z rodzimym oknem, które rozwiązałem przy użyciu wątku STA.

var thread = new Thread(() => { 
      // Your code here 
}); 
thread.TrySetApartmentState(ApartmentState.STA); 
thread.Start(); 
+0

Nie jestem pewien, jak to wpłynie, ale mimo to spróbowałem, to nie pomogło. –