0

我在我的 c# 应用程序中使用 flashwindowex winapi 在图标托盘中闪烁 IE 窗口。当我在代码中添加断点并在调试中运行时,代码运行良好。但是当断点被删除时,相同的代码不起作用。

这是一个控制台应用程序,我正在使用一些 Windows api 通过其名称查找创建的 IE 进程的句柄。进程的句柄被进一步传递给FlashWindowEXWINAPI 用于刷新进程。

public static System.IntPtr hnd = IntPtr.Zero;
public delegate bool CallBackPtr(IntPtr hwnd, int lParam);
public static CallBackPtr callBackPtr;
public const UInt32 FLASH_T = 3;
public const UInt32 FLASH_S = 12;

static void Main(string[] args)
{
    try
    {
        OrigCode();
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
    Console.ReadLine();
}

public static void OrigCode()
{
    string strPzszPath = string.Empty;
    string strCommandLine = string.Empty;
    string strpath1 = "http://localhost/Till/Default.aspx";

    strPzszPath = string.Concat(strPzszPath, strpath1);
    strPzszPath = string.Concat(strPzszPath, "?TSCashierID=JILL&TSBalPeriod=2&TSBalDate=2015-06-02");
    strCommandLine = strPzszPath;
    Process procRequested = new Process();

    ////Create the process in minimised mode by default
    procRequested.StartInfo.WindowStyle = ProcessWindowStyle.Minimized;
    procRequested.StartInfo.UseShellExecute = false;

    ////Get the file name in which process is required to be started
    procRequested.StartInfo.FileName = @"C:\Program Files\Internet Explorer\IExplore.exe";

    procRequested.StartInfo.Arguments = strCommandLine;

    ////Start the process, process should be created in minimised mode
    procRequested.Start();

    callBackPtr = new CallBackPtr(SetFocusEnum);
    int intResult = EnumWindows(callBackPtr, 0);

    FLASHWINFO fi = new FLASHWINFO();
    fi.cbSize = Convert.ToUInt32(Marshal.SizeOf(fi));
    fi.hwnd = hnd;
    fi.dwFlags = FLASH_T | FLASH_S;
    fi.ucount = UInt32.MaxValue;
    fi.dwTimeout = 0;
    FlashWindowEx(ref fi);
}

private static bool SetFocusEnum(IntPtr hWnd, int intLParam)
{
    int intSize = GetWindowTextLength(hWnd);
    try
    {

        if (intLParam == 0) //Process created so check by name
        {
            if (intSize++ > 0)
            {

                //Capture the running window name
                StringBuilder sbWindowName = new StringBuilder(intSize);
                GetWindowText(hWnd, sbWindowName, intSize);
                //Capture the running process with the window name
                if (sbWindowName.ToString().Contains("My Web Application Title"))
                {
                //Capture the handle which will be used to set the focus
                hnd = hWnd;
                }
            }
        }
    }
    catch (Exception ex)
    {
    }
    finally
    {
    }
    return true;
}

以下是我使用的winapi函数:

[DllImport("user32.dll", CharSet = CharSet.Unicode)]
internal static extern int EnumWindows(CallBackPtr callPtr, int intProc);

[DllImport("user32.dll", CharSet = CharSet.Unicode)]
internal static extern int GetWindowTextLength(IntPtr intptrHwnd);

[DllImport("user32.dll", CharSet = CharSet.Unicode)]
internal static extern int GetWindowText(IntPtr intptrHwnd, StringBuilder strText, int intMaxCount);

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool FlashWindowEx(ref FLASHWINFO pwfi);

[StructLayout(LayoutKind.Sequential)]
private struct FLASHWINFO
{
    public UInt32 cbSize;
    public IntPtr hwnd;
    public UInt32 dwFlags;
    public UInt32 ucount;
    public UInt32 dwTimeout;
}
4

1 回答 1

0

就像我在评论中所说的那样,这里的问题是加载页面需要很长时间才能在您执行EnumWindows()函数时更改窗口的文本。您使用的代码几乎立即执行,而打开进程并加载页面需要几百毫秒到几秒钟。添加延迟是解决问题的最简单的解决方法。

这是我所做的:

procRequested.Start();
procRequested.WaitForInputIdle();

System.Threading.Thread.Sleep(750); //Wait for approximately 750 ms.

通常建议不要使用Thread.Sleep(),但由于您在控制台应用程序中,除了在它运行的一小段时间内阻止用户输入之外没有太大区别。

您可能还注意到我添加了对 的调用Process.WaitForInputIdle(),这是为了让您的应用程序等到进程完成其启动过程(例如加载资源,或在应用程序实际启动之前 Windows 对进程执行的任何操作),以便我们知道当我们可以期望窗口实际显示时。

如果您有时感觉或体验到 750 毫秒的延迟还不够,请尝试将其提高到 1250 或类似的值。


编辑:

由于(如您所说)聚焦窗口不会闪烁,因此您可以将窗口句柄存储到先前聚焦的窗口,并在让FlashWindowEx代码执行之前使用它再次聚焦窗口。

为此,您将需要两个 WinAPI 调用:

[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetForegroundWindow(IntPtr hWnd);

然后你只需在这里使用这两个函数:

IntPtr focusedhWnd = GetForegroundWindow(); //Get the window handle to the currently focused window.

procRequested.Start();
procRequested.WaitForInputIdle();

System.Threading.Thread.Sleep(750); //Wait for approximately 750 ms.

callBackPtr = new CallBackPtr(SetFocusEnum);
int intResult = EnumWindows(callBackPtr, 0);

SetForegroundWindow(focusedhWnd); //Focus the previously focused window again.

FLASHWINFO fi = new FLASHWINFO();
fi.cbSize = Convert.ToUInt32(Marshal.SizeOf(fi));
fi.hwnd = hnd;
fi.dwFlags = FLASH_T | FLASH_S;
fi.ucount = UInt32.MaxValue;
fi.dwTimeout = 0;
FlashWindowEx(ref fi);
于 2016-08-08T12:46:58.593 回答