Я пытаюсь встроить osk в окно wpf или пользовательский элемент управления, и я нашел приведенный ниже код, и он работает для блокнота, но для tabtip.exe он говорит, что у него нет графического интерфейса??
Ошибка функции WaitForInputIdle. Это может быть связано с тем, что у процесса нет графического интерфейса.
Я попытался позволить ему спать некоторое время вместо вызова метода waitForInputIdle, но он выдает другое исключение:
Процесс завершен, поэтому запрошенная информация недоступна.
Но в моем диспетчере задач я все еще вижу запущенный 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();
}
}
}
Редактировать: Вдохновленный комментарием Рене, я попытался получить ptr окна, как показано ниже, и использовал spy++, чтобы убедиться, что адрес, который дает FindWindow, указывает на правильное окно, но он все еще не движется:
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);
Редактировать 2: Моя первая мысль заключалась в том, что размер подсказки вкладки нельзя изменить, но затем я заметил поведение, когда я пытаюсь переместить окно на два разных экрана, оно изменит размер, чтобы соответствовать размеру экрана, поэтому я уверен, что там должен быть способ изменить размер, поэтому я запустил spy++(x64) для проверки:
Редактировать 3: после того, как я немного поработал с API-интерфейсом user32 и без прогресса, я попытался использовать сканер памяти для сканирования позиции x и y вкладки и изменить ее, однако он не обновляется до тех пор, пока не будет запущена перерисовка, я задаюсь вопросом о возможности идти по этому пути.