2013-05-21 44 views
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"-type example(其中我的方法是從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"); 
     } 
    } 
} 

謝謝。

+0

郵政ObtainPrinterPort'的'的內容。 –

回答

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(); 
+1

不!這不是一個很好的計劃! –

+0

@MartinJames請解釋一下。 – Blorgbeard

+0

Downvoter關心評論? – Blorgbeard

相關問題