Winapi Win32:IProgressDialog将不会消失,直到您将鼠标移到它上面
我在用电话。最糟糕的是当我打电话时:Winapi Win32:IProgressDialog将不会消失,直到您将鼠标移到它上面,winapi,message-queue,Winapi,Message Queue,我在用电话。最糟糕的是当我打电话时: progressDialog.StopProgressDialog(); 它不会消失。它一直在屏幕上,直到用户将鼠标移到它上面——然后它突然消失了 对StopProgressDialog的调用会立即返回(即,它不是同步调用)。我可以通过在电话返回后做一些事情来证明这一点: private void button1_Click(object sender, EventArgs e) { //Force red background to prove w
progressDialog.StopProgressDialog();
它不会消失。它一直在屏幕上,直到用户将鼠标移到它上面——然后它突然消失了
对StopProgressDialog
的调用会立即返回(即,它不是同步调用)。我可以通过在电话返回后做一些事情来证明这一点:
private void button1_Click(object sender, EventArgs e)
{
//Force red background to prove we've started
this.BackColor = Color.Red;
this.Refresh();
//Start a progress dialog
IProgressDialog pd = (IProgressDialog)new ProgressDialog();
pd.StartProgressDialog(this.Handle, null, PROGDLG.Normal, IntPtr.Zero);
//The long running operation
System.Threading.Thread.Sleep(10000);
//Stop the progress dialog
pd.SetLine(1, "Stopping Progress Dialog", false, IntPtr.Zero);
pd.StopProgressDialog();
pd = null;
//Return form to normal color to prove we've stopped.
this.BackColor = SystemColors.Control;
this.Refresh();
}
表格:
- 开始变灰
- 变成红色表示我们已经盯着看了
- 返回到灰色显示我们已呼叫停止
StopProgressDialog
的调用已返回,但进度对话框仍在那里,模拟我,显示以下消息:
停止进度对话框
10秒钟内不会出现 此外,进度对话框直到
System.Threading.Thread.Sleep(10000);
十秒钟的睡眠结束了
不限于.NET WinForms 同样的代码在Delphi中也会失败,Delphi也是windows窗口的对象包装器:
procedure TForm1.Button1Click(Sender: TObject);
var
pd: IProgressDialog;
begin
Self.Color := clRed;
Self.Repaint;
pd := CoProgressDialog.Create;
pd.StartProgressDialog(Self.Handle, nil, PROGDLG_NORMAL, nil);
Sleep(10000);
pd.SetLine(1, StringToOleStr('Stopping Progress Dialog'), False, nil);
pd.StopProgressDialog;
pd := nil;
Self.Color := clBtnFace;
Self.Repaint;
end;
蜜饯 如果
StopProgressDialog
失败,将引发异常
IProgressDialog中的大多数方法在翻译成C#(或Delphi)时,都使用编译器的自动机制将失败的COM HRESULT转换为本机语言异常
换句话说,如果COM调用返回错误HRESULT(即小于零的值),则以下两个签名将引发异常:
鉴于以下内容,您可以查看HRESULT并自己做出反应:
//C#
[PreserveSig]
int StopProgressDialog();
//Delphi
function StopProgressDialog: HRESULT; stdcall;
HRESULT是一个32位的值。如果设置高位(或值为负值),则为错误
我使用的是前一种语法。因此,如果StopProgressDialog
返回错误,它将自动转换为语言异常
注意:仅针对SaG,我使用了[PreserveSig]
语法,返回的HRESULT为零
MsgWait? 该症状与以下情况类似,与不正确使用PeekMessage和MsgWaitForMultipleObjects有关: “有时,我的程序会卡住并 报告的记录比它少一条 应该的,我得摇动鼠标 获取要更新的值。稍后 再长一点,它就落后两个了 三个……”
但这意味着失败发生在IProgressDialog中,因为它在CLR.NET WinForms和本机Win32代码上同样失败。检查StopProgressDialog方法的返回值,也许这将为您提供有关发生了什么的更多信息: HRESULT STOPPROGRESS对话框(无效) 如果成功,则返回S_OK,否则返回错误值
完整的p/Invoke签名,但以下是简化版,便于阅读:
[ComImport]
[Guid("EBBC7C04-315E-11d2-B62F-006097DF5BD4")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IProgressDialog
{
void StartProgressDialog(IntPtr hwndParent,
[MarshalAs(UnmanagedType.IUnknown)] object punkEnableModless, //IUnknown
PROGDLG dwFlags, //DWORD
IntPtr pvResevered //LPCVOID
);
void StopProgressDialog();
void SetTitle(
[MarshalAs(UnmanagedType.LPWStr)] string pwzTitle //LPCWSTR
);
void SetAnimation(
IntPtr hInstAnimation, //HINSTANCE
ushort idAnimation //UINT
);
[PreserveSig]
[return: MarshalAs(UnmanagedType.Bool)]
bool HasUserCancelled();
void SetProgress(
uint dwCompleted, //DWORD
uint dwTotal //DWORD
);
void SetProgress64(
ulong ullCompleted, //ULONGLONG
ulong ullTotal //ULONGLONG
);
void SetLine(
uint dwLineNum, //DWORD
[MarshalAs(UnmanagedType.LPWStr)] string pwzString, //LPCWSTR
[MarshalAs(UnmanagedType.VariantBool)] bool fCompactPath, //BOOL
IntPtr pvResevered //LPCVOID
);
void SetCancelMsg(
[MarshalAs(UnmanagedType.LPWStr)] string pwzCancelMsg,
object pvResevered
);
void Timer(PDTIMER dwTimerAction, object pvResevered);
}
注意:几乎所有方法的签名都遵循正确的COM规则。除了HasUserCancelled
。它不遵循COM类中方法的签名规则。所有方法都应返回HRESULT,返回值应位于out retval
参数中HasUserCancelled实际上返回一个布尔值
注意:几乎所有这些世界都是你的。欧洲除外。不要在那里着陆
注意:您几乎所有的基地都属于我们。除了
WhatYouSay
。主灯亮起。 < P>为了真正隐藏对话框,我已经将下面的内容添加到我的C++包装类:
void CProgressDlg::Stop()
{
if ((m_isVisible)&&(m_bValid))
{
HWND hDlgWnd = NULL;
//Sometimes the progress dialog sticks around after stopping it,
//until the mouse pointer is moved over it or some other triggers.
//This process finds the hwnd of the progress dialog and hides it
//immediately.
IOleWindow *pOleWindow;
HRESULT hr=m_pIDlg->QueryInterface(IID_IOleWindow,(LPVOID *)&pOleWindow);
if(SUCCEEDED(hr))
{
hr=pOleWindow->GetWindow(&hDlgWnd);
if(FAILED(hr))
{
hDlgWnd = NULL;
}
pOleWindow->Release();
}
m_pIDlg->StopProgressDialog();
if (hDlgWnd)
ShowWindow(hDlgWnd, SW_HIDE);
m_isVisible = false;
m_pIDlg->Release();
m_bValid = false;
}
}
这是C++,但是你应该能够将它适应C,而不会有太多的问题。
我不使用ReaveSimg(或者SabeCalor)。这个bug已经困扰了我一段时间。谢谢你的回答,斯蒂芬。void CProgressDlg::Stop()
{
if ((m_isVisible)&&(m_bValid))
{
HWND hDlgWnd = NULL;
//Sometimes the progress dialog sticks around after stopping it,
//until the mouse pointer is moved over it or some other triggers.
//This process finds the hwnd of the progress dialog and hides it
//immediately.
IOleWindow *pOleWindow;
HRESULT hr=m_pIDlg->QueryInterface(IID_IOleWindow,(LPVOID *)&pOleWindow);
if(SUCCEEDED(hr))
{
hr=pOleWindow->GetWindow(&hDlgWnd);
if(FAILED(hr))
{
hDlgWnd = NULL;
}
pOleWindow->Release();
}
m_pIDlg->StopProgressDialog();
if (hDlgWnd)
ShowWindow(hDlgWnd, SW_HIDE);
m_isVisible = false;
m_pIDlg->Release();
m_bValid = false;
}
}