2

Win32の進行状況ダイアログを使用しています。最もひどいことは、私が電話するときです:

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); 

10秒の睡眠が終わりました。


.NETWinFormsに限定されません

同じコードが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;

PreserveSig

StopProgressDialog失敗した場合は例外がスローされます。

IProgressDialogのほとんどのメソッドは、C#(またはDelphi)に変換されると、失敗したCOMHRESULTSを母国語の例外に変換するコンパイラの自動メカニズムを使用します。

つまり、COM呼び出しがエラーHRESULT(つまり、ゼロ未満の値)を返した場合、次の2つのシグニチャは例外をスローします。

//C#
void StopProgressDialog();

//Delphi
procedure StopProgressDialog; safecall;

以下では、HRESULTを確認し、自分で反応することができます。

//C#
[PreserveSig]
int StopProgressDialog();

//Delphi
function StopProgressDialog: HRESULT; stdcall;

HRESULTは32ビット値です。上位ビットが設定されている場合(または値が負の場合)、エラーになります。

私は前者の構文を使用しています。したがって、StopProgressDialogがエラーを返す場合、それは自動的に言語例外に変換されます。

注:構文を使用したSaGの[PreserveSig]場合、返されるHRESULTはゼロです。


MsgWait?

症状は、レイモンド・チェンがかつて説明したものと似ています。これは、PeekMessageとそれに続くMsgWaitForMultipleObjectsの誤った使用に関係しています。

「プログラムが動かなくなって、必要なレコードより1つ少ないレコードが報告されることがあります。更新する値を取得するには、マウスを動かす必要があります。しばらくすると、2つ遅れ、次に3つ遅れます...」

ただし、CLR .NET WinFormsとネイティブWin32コードで同じように失敗するため、失敗はIProgressDialogにあることを意味します。

4

3 に答える 3

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#に問題なく適合させることができるはずです。

于 2009-01-16T21:50:00.183 に答える
0

StopProgressDialogメソッドの戻り値を確認してください。これにより、何が起こっているかについての詳細情報が得られる可能性があります。

HRESULT StopProgressDialog(VOID);

成功した場合はS_OKを返し、そうでない場合はエラー値を返します。

于 2008-12-18T16:18:51.350 に答える
0

完全な 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 retvalHasUserCancelledは実際にはブール値を返します。

注:これらの世界のほとんどすべてがあなたのものです。を除いてEuropa。そこに着陸しようとしないでください。

注:あなたの基地のほとんどは私たちのものです。を除いてWhatYouSay。メインライト点灯。

于 2008-12-18T16:29:45.290 に答える