如何记录第三方应用程序中显示消息框的时间?

时间:2010-10-18 17:51:08

标签: c# logging messagebox

情况如下:

我们有第三方应用程序,间歇性地显示错误消息。通常,当没有人在办公室时会发生错误,因此我们不知道消息框正好弹出的时间。我们正在与我们的供应商合作以确定问题所在,并且他们想要确切地知道错误发生的时间,以便我们可以在发生错误时为他们提供网络条件等。应用程序不会在任何地方记录错误消息,因此我的任务是以某种方式记录它。

我有C#.NET作为我的工具。到目前为止,我找到的最接近解决方案的东西是FindWindow和EnumChildWindows,或者挂钩到Windows消息中。我是最近的大学毕业生,刚开始我的工作,所以这两条路线对我来说都相当复杂。在我投入大量时间试图学习我需要尝试使其中一种方法起作用之前,我想在这里查看是否有更简单的解决方案。

我真正需要的是在出现消息框时记录以及有关消息框的一些识别信息。没有必要仅记录来自相关应用程序的消息。

感谢您的帮助。如果我需要澄清任何事情,请告诉我。

编辑:

我试图用Hans的建议和参考编写代码。我非常依赖他的代码示例。现在我有一个接受进程名称的表单。单击按钮将创建以下类的实例。我用记事本做了一些测试,但它只是通过findMessageBox方法循环,​​即使我打开了一个对话框。我尝试使用EnumChildWindows而不是EnumThreadWindows,同样的事情发生了。我确认该程序使用Spy ++具有正确的PID。我很感激有关我需要修复的建议。

编辑:

现在正在运作。非常感谢你的帮助。我将错误的值从GetWindowProcessThreadId传递给EnumThreadWindows。我仍然会对它进行一些处理,因为我可以清理一些并且我不希望连续记录打开的对话框,但这些都是微不足道的事情。我已经发布了我现在使用的主要功能代码,以防万一其他人将来必须做类似的事情:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.IO;
using System.Windows.Forms;

namespace LogDialog
{
class DialogLogger
{
    TextWriter log = new StreamWriter(@"C:\ErrorLog\ErrorLog.txt");
    private Timer mTimer;
    private uint lpdwProcessId;
    private IntPtr mhwnd;
    uint threadID;

    //*************P/Invoke Declarations*************//

    private delegate bool EnumThreadWndProc(IntPtr hwnd, IntPtr lp);
    private delegate bool EnumWindowsProc(IntPtr hwnd, IntPtr lp);

    [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
    private static extern bool EnumThreadWindows(int dwThreadId, EnumThreadWndProc callback, IntPtr lParam);

    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    static extern int GetClassName(IntPtr hwnd, StringBuilder buffer, int buflen);

    //Retrieves the identifier of the thread that created the specified window and, optionally, the identifier of the process that created the window. 
    [DllImport("user32.dll", SetLastError = true)]
    static extern uint GetWindowThreadProcessId(IntPtr hwnd, out uint lpdwProcessId);

    //***********************************************//

    //Constructor; initiates timer
    public DialogLogger(string processName)
    {
        setWindowProcessID(processName);                    //set process ID
        mTimer = new Timer();                               //create timer for logging
        mTimer.Interval = 50;                               //set interval
        mTimer.Enabled = true;                              //enable
        mTimer.Tick += new EventHandler(findMessageBox);    //set event handler
    }

    private void setWindowProcessID(string processName)
    {
        mhwnd = Process.GetProcessesByName(processName)[0].MainWindowHandle;
        threadID = GetWindowThreadProcessId(mhwnd, out lpdwProcessId);
    }

    //Enumerates windows to find a message box
    private void findMessageBox(object sender, EventArgs e)
    {
        EnumThreadWndProc callback = new EnumThreadWndProc(checkDialogWindow);
        EnumThreadWindows((int)threadID, callback, IntPtr.Zero);
        GC.KeepAlive(callback);
    }

    //Checks if hwnd is a dialog
    private bool checkDialogWindow(IntPtr hwnd, IntPtr lp)
    {
        StringBuilder sb = new StringBuilder(260);
        GetClassName(hwnd, sb, sb.Capacity);

        if (sb.ToString() != "#32770") return true;

        log.WriteLine("Error Logged: {0}", DateTime.Now.ToLongTimeString());

        return false;
    }
}
}

3 个答案:

答案 0 :(得分:1)

他们正在催促你,完全清楚这并不容易实现。添加日志记录对他们来说完全是微不足道的,如果他们的应用程序对网络条件敏感,他们应该已经这样做了。对这一要求最积极的看法是,他们希望你能够自己解决这个问题。可能发生。与你的主管交谈并指出这一点。

答案 1 :(得分:0)

这个简单方法怎么样:每2分钟创建一个screen capture,然后第二天查看图像文件?

答案 2 :(得分:0)

如果你可以附加一个调试器,它应该是相当简单的:)