2

フォームを作成していますが、スレッドを使用して WMI クエリからいくつかの結果を取得し、フォームがユーザーにフリーズすることなくテキスト ボックスに表示しようとしています。ただし、以下のコードを使用し、デバッグ時に Break-All を使用すると、コードはそのままになりますgetPrinterThread.Join()。私は何かが欠けているに違いないことを知っています。

私の目的は、ObtainPrinterPort メソッドを最後まで実行するスレッドを取得してから、InstallPrinterPort メソッドを最後まで実行するスレッドを取得することです。以下のコードを別のメソッドのインライン コードとして使用しています。コードは別のクラスなどにはなく、バックグラウンド ワーカーもありません。これまでに見たすべての例は、私を混乱させるだけだったからです。

ここに私の確かに悪いスレッドの試みがあります:

Thread printThread = new Thread(ObtainPrinterPort);
printThread.Start();
while (!printThread.IsAlive) ;
Thread.Sleep(1);
printThread.Join();         // Form sits and does nothing; Break-all reveals this line as statement being executed.

Thread installThread = new Thread(InstallPrinterPort);
installThread.Start();
while (!installThread.IsAlive);
Thread.Sleep(1);
installThread.Join();

安全で、メソッドで発生した結果をテキストボックスのユーザーに表示できるようにする簡単な方法はありますか? フォーム クラスに記述したインスタンス変数/メソッド/コードを引き続き使用できるようにする方法があることを願っています。 m 「DoWork」タイプの例を実装します(私のメソッドは DoWork メソッド/コンストラクターまたは Worker クラスから呼び出されます)。

ユーザーに結果を表示するために、私のメソッドはスレッドからテキストボックスにテキストを返す必要があることに注意してください。機能する場合はスレッドからテキストを返すことができると想定しているコードがありますが、提案/ヘルプがこれを念頭に置いていることを確認したかっただけです。私が使用しているコードは以下のとおりです。

public void AppendTextBox(string value)
{
    if (InvokeRequired)
    {
        this.Invoke(new Action<string>(AppendTextBox), new object[] { value });
        return;
    }

    txtResults.Text += value;
}

価値のあるものとして、ここに私の ObtainPrinterPort メソッドとそれに付随する CreateNewConnection メソッドを示します... InstallPrinterPort メソッドは非常に似ているため、投稿してもあまり明らかになりません。

private ManagementScope CreateNewConnection(string server, string userID, string password)
{
    string serverString = @"\\" + server + @"\root\cimv2";
    ManagementScope scope = new ManagementScope(serverString);

    try
    {
        ConnectionOptions options = new ConnectionOptions
        {
            Username = userID,
            Password = password,
            Impersonation = ImpersonationLevel.Impersonate,
            EnablePrivileges = true

        };
        scope.Options = options;
        scope.Connect();
    }
    catch (ManagementException err)
    {
        MessageBox.Show("An error occurred while querying for WMI data: " +
                        err.Message);
    }
    catch (System.UnauthorizedAccessException unauthorizedErr)
    {
        MessageBox.Show("Connection error (user name or password might be incorrect): " +                              unauthorizedErr.Message);
    }

    return scope;
}

private void ObtainPrinterPort()
{
    string computerName = "";
    string userID = "";
    string password = "";
    string printerQuery = "SELECT * FROM Win32_Printer WHERE Name = ";
    string portQuery = "SELECT * FROM Win32_TCPIPPrinterPort WHERE Name = ";
    string search = "";
    SelectQuery query;

    foreach (var s in lstServer)
    {
        computerName = s.ServerName;
        userID = s.UserID;
        password = s.Password;
    }

    ManagementScope scope = CreateNewConnection(computerName, userID, password);

    foreach (Printers p in lstPrinters)
    {
        AppendTextBox("Obtaining printer/port info for " + p.PrinterName + "\r\n");

        search = printerQuery + "'" + p.PrinterName + "'";

        query = new SelectQuery(search);

        try
        {
            using (var searcher = new ManagementObjectSearcher(scope, query))
            {
                ManagementObjectCollection printers = searcher.Get();

                if (printers.Count > 0)
                {
                    AppendTextBox("\tStoring printer properties for " + p.PrinterName + "\r\n");

                    foreach (ManagementObject mo in printers)
                    {
                        StorePrinterProperties(p, mo);
                    }
                }
                else
                {
                    lstPrinterExceptions.Add("Printer: " + p.PrinterName);

                    AppendTextBox("\t**Printer " + p.PrinterName + " not found**\r\n");
                }
            }
        }
        catch (Exception exception)
        {
            MessageBox.Show("Error: " + exception.Message, "Error",
                            MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
        }

        if (!lstPrinterExceptions.Contains("Printer: " + p.PrinterName)
           && !lstPrinterExceptions.Contains("Port: " + p.PortName))
        {
            search = portQuery + "'" + p.PortName + "'";

            query = new SelectQuery(search);

            try
            {
                using (var searcher = new ManagementObjectSearcher(scope, query))
                {
                    ManagementObjectCollection ports = searcher.Get();

                    if (ports.Count > 0)
                    {
                        AppendTextBox("\tStoring port properties for " + p.PortName + " (" + p.PrinterName + ")\r\n");

                        foreach (ManagementObject mo in ports)
                        {
                            StorePortProperties(p, mo);
                        }
                    }
                    else
                    {
                        lstPrinterExceptions.Add("Port: " + p.PortName);

                        AppendTextBox("\t**Port " + p.PortName + " for " + p.PrinterName + " not found**\r\n");
                    }
                }
            }
            catch (Exception exception)
            {
                MessageBox.Show("Error: " + exception.Message, "Error",
                                MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }

            AppendTextBox("\tSuccessfully obtained printer/port info for " + p.PrinterName + "\r\n");
        }
    }
}

ありがとう。

4

1 に答える 1

0

あなたの問題は、メインスレッドが処理できるようInvokeに呼び出しがブロックされているDoEventsのに、メインスレッドがブロックされていることThread.Joinです。デッドロックがあります。

これは、UI スレッドをブロックせずにスレッドを実行する方法です。Thread.Join他のスレッドが終了するまでブロックするため、ここでは最大 100 ミリ秒だけブロックしDoEvents、フォームがメッセージに応答できるように呼び出し (Invoke他のスレッドからの呼び出しの処理を含む)、バックグラウンド スレッドが完了するまでループします。

Thread printThread = new Thread(ObtainPrinterPort);
printThread.Start();
while (printThread.IsAlive) {
    Application.DoEvents();        
    printThread.Join(100);        
}

このようなループでの呼び出しDoEventsは少しハックですが、うまくいきます。

を調べることもできますBackgroundWorker。これにより、全体がより安全で簡単になります.

簡単な例:

var bw = new BackgroundWorker();            
bw.DoWork += (worker, args) => {
    ObtainPrinterPort();
};
bw.RunWorkerAsync();
于 2013-05-21T00:10:04.333 に答える