gpt4 book ai didi

c# - 从不使用标签控件的对话框中获取文本?

转载 作者:可可西里 更新时间:2023-11-01 08:27:03 26 4
gpt4 key购买 nike

这是我之前问题的延续 How to supress a dialog box an Inproc COM Server displays .


背景:

回顾一下我的情况:我有一个由第 3 方用 Delphi 编写的 Inproc COM 服务器。如果我调用的函数之一捕获特定类型的错误,它将显示一个错误消息对话框。问题是我正在尝试批量处理数据,而我正在使用的数据源导致该错误对话框弹出很多(感谢我之前问题的回答,它现在自动关闭并且我能够运行它到完成后,它会显示对话框并要求有人按 OK 9923 次)。进程阻塞,直到消息框关闭。


问题:

我希望更好地记录错误对话框中所说的内容。但是,任何获取对话框正文的尝试都失败了。

Image of Dialog Box

//Snip

private void StartWindowListener()
{
//Queue the watcher on the message pump if we are not watching.
if (_watcherRunning == false)
{
_watcherRunning = true;
_dummyForm.BeginInvoke(new Action(() =>
{
_watcherRunning = false;

//If we are not inside the com object don't enumerate.
if (_insideCom == false) return;

// Enumerate windows to find dialogs
EnumThreadWndProc callback = new EnumThreadWndProc(CheckWindow);
EnumThreadWindows(GetCurrentThreadId(), callback, IntPtr.Zero);
GC.KeepAlive(callback);
}));
}
}

private bool CheckWindow(IntPtr hWnd, IntPtr lp)
{
// Checks if hWnd is the expected dialog
StringBuilder sb = new StringBuilder(260);
GetClassName(hWnd, sb, sb.Capacity);
if (sb.ToString() == "TMessageForm")
{
//This returns the dialog box's title
GetWindowText(hWnd, sb, sb.Capacity);

//This returns IntPtr.Zero
var hDialogText = GetDlgItem(hWnd, 0xFFFF);
if (hDialogText != IntPtr.Zero)
GetWindowText(hDialogText, sb, sb.Capacity);

//This returns a empty string
GetDlgItemText(hWnd, 0xFFFF, sb, sb.Capacity);


//Only sees the OK button.
IntPtr hCtl = IntPtr.Zero;
HashSet<IntPtr> seen = new HashSet<IntPtr>();
while ((hCtl = GetNextDlgGroupItem(hWnd, hCtl, false)) != IntPtr.Zero)
{
//When we see the same control twice, break out of the loop.
if (seen.Add(hCtl) == false)
break;

GetClassName(hCtl, sb, sb.Capacity);
SendMessage(hCtl, WM_GETTEXT, sb.Capacity, sb)

//Close the dialog by sending WM_CLOSE to the window
SendMessage(hWnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
}

//Snip...
}
return true;
}

//Snip...

// P/Invoke declarations
const int WM_CLOSE = 0x0010;
private delegate bool EnumThreadWndProc(IntPtr hWnd, IntPtr lp);
[DllImport("user32.dll")]
private static extern bool EnumThreadWindows(int tid, EnumThreadWndProc callback, IntPtr lp);
[DllImport("user32.dll")]
private static extern int GetClassName(IntPtr hWnd, StringBuilder buffer, int buflen);
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
[DllImport("kernel32.dll")]
private static extern int GetCurrentThreadId();

我想我可能在对话框开始添加文本之前就打断了它(当我打断上面的代码时它还没有完全绘制)。然而,在开始枚举之前将 Application.DoEvents 放入 StartWindowListener 允许对话框完全绘制,但我仍然得到与我用上面的代码发布的相同的结果。

在对话框中按 Ctrl-C 可以正常工作,所以我可以在紧要关头使用它,但由于我必须重复这个 9923 次,所以我想避免以编程方式使用它。

是否有任何其他方法可以尝试从消息框中获取文本?

最佳答案

感谢Sertac's comment我发现 Delphi 消息框中的文本不是窗口对象,它们是用“DrawText”方法绘制的。我用了EasyHook拦截 Windows API 调用,我现在可以获取我关心的文本。

////It appears that DrawText always calls DrawTextEx so it is getting intercepted twice.
//// Only need to hook DrawTextEx
static EasyHook.LocalHook _drawTextExAHook;

//Snip...

public override void Run()
{
//Snip...

IntPtr drawTextExAPtr = EasyHook.LocalHook.GetProcAddress("user32", "DrawTextExA");
_drawTextExAHook = EasyHook.LocalHook.Create(drawTextExAPtr, new DrawTextExDelegate(DrawTextEx_Hooked), null);

//The COM stuff must be run in a STA Thread so we can intercept the message boxes that it throws up.
var staThread = new Thread(() =>
{
try
{
var threadID = new[] { GetCurrentThreadId() };
//Enable the hook on the current thread.
_drawTextExAHook.ThreadACL.SetInclusiveACL(threadID);

//Tell the dummy form to start ComThread
_dummyForm = new DummyForm(ComThread);
Application.Run(_dummyForm);
}
finally
{
if(_drawTextExAHook != null)
_drawTextExAHook.Dispose();
}
});
staThread.SetApartmentState(ApartmentState.STA);
staThread.Name = "Com Thread";
staThread.Start();

//Wait for the Com Thread to finish.
staThread.Join();

}

//Snip...

private delegate int DrawTextExDelegate(IntPtr hdc, string lpchText, int cchText,
ref Rect lprc, uint dwDTFormat, ref DRAWTEXTPARAMS lpDTParams);

private int DrawTextEx_Hooked(IntPtr hdc, string lpchText, int cchText, ref Rect lprc,
uint dwDTFormat, ref DRAWTEXTPARAMS lpDTParams)
{
LogErrorText(lpchText);
return DrawTextEx(hdc, lpchText, cchText, ref lprc, dwDTFormat, ref lpDTParams);
}

[DllImport("user32.dll")]
static extern int DrawTextEx(IntPtr hdc, string lpchText, int cchText,
ref Rect lprc, uint dwDTFormat, ref DRAWTEXTPARAMS lpDTParams);

关于c# - 从不使用标签控件的对话框中获取文本?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12570167/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com