我正在使用Win32 progress dialog。最可靠的是,当我打电话时:
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
的调用已经返回,除了进度对话框仍然在那里,嘲笑我,显示消息:
停止进度对话框
此外,在
之前,屏幕上不会显示进度对话框System.Threading.Thread.Sleep(10000);
十秒钟的睡眠结束了。
同样的代码也在Delphi中失败,Delphi也是Window窗口的对象包装器:
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 HRESULTS转换为本机语言异常的自动机制。
换句话说,如果COM调用返回错误HRESULT(即小于零的值),则以下两个签名将抛出异常:
//C#
void StopProgressDialog();
//Delphi
procedure StopProgressDialog; safecall;
以下内容让您看到HRESULT并做出反应:
//C#
[PreserveSig]
int StopProgressDialog();
//Delphi
function StopProgressDialog: HRESULT; stdcall;
HRESULT是32位值。如果设置了高位(或者值为负),那就是错误。
我正在使用以前的语法。因此,如果StopProgressDialog
返回错误,它将自动转换为语言异常。
注意:仅针对SaG我使用[PreserveSig]
语法,返回的HRESULT为零;
症状类似于Raymond Chen described once,这与错误使用PeekMessage后跟MsgWaitForMultipleObjects有关:
“有时我的程序卡住了 报告的记录少于它 应该。我必须摇动鼠标 获取要更新的值。过了一会儿 然后,它会落后两个 3 ...“
但这意味着失败在IProgressDialog中,因为它在CLR .NET WinForms和本机Win32代码上同样失败。
答案 0 :(得分:4)
为了真正隐藏对话框,我已将以下内容添加到我的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#。
答案 1 :(得分:0)
检查StopProgressDialog方法的返回值,这可能会为您提供有关正在发生的事情的更多信息:
HRESULT StopProgressDialog(VOID);
如果成功则返回S_OK,否则返回错误值。
答案 2 :(得分:0)
完整的P / Invoke签名is available,但这里是精简版本以便于阅读:
[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 实际上返回一个布尔值。
注意:几乎所有这些世界都是你的。 Europa
除外。试图不在那里着陆。
注意:您的几乎所有基地都属于我们。 WhatYouSay
除外。主灯亮。