Custom Windows

Tags: v6

FAQ on UI and .Net

If the dialog windows of SyrveFront API are not enough, the plugin can display its own windows, but there are some nuances to consider.

First, the host process of the plugin does not, by default, contain the necessary UI STA thread. The plugin must create it on its own. Example code:

ctor()
{
    var windowThread = new Thread(EntryPoint);
    windowThread.SetApartmentState(ApartmentState.STA);
    windowThread.Start();
}
...
private void EntryPoint()
{
    Window window = new MyWindow();
    window.ShowDialog();
}

Second, a window opened by a background process does not have focus by default, so input events will be directed to the previously active window (i.e., the SyrveFront window). According to Microsoft’s design, an application cannot become active on its own; it can only be passed the baton by the previous active window, or focus can be assigned by the user. However, the latter can be simulated programmatically:

public static void ClickWindow(Window wnd)
{
    try
    {
        var wih = new WindowInteropHelper(wnd);
        WinApi.RECT rect;
        WinApi.GetWindowRect(new HandleRef(wnd, wih.Handle), out rect);
        var x = rect.Left + (rect.Right - rect.Left) / 2;
        var y = rect.Top + (rect.Bottom - rect.Top) / 4;
        WinApi.LeftMouseClick(x, y);
    }
    catch (Exception) { }
}

Third, the plugin’s window, being an independent window, may end up behind the SyrveFront window. The always-on-top mode is also not a panacea, as there may be other topmost windows (including the SyrveFront application itself). The plugin can bind its window as a child to the SyrveFront window using the WinApi function SetParent. Although the hwnd of the front window is not published in the API, the plugin can find it on its own.