Reputation: 553
[C# .NET Windows Form WMI]
I'm pretty new at C#, but I have experience with VBScript and I'm trying to convert a script I wrote to C#. Instead of just using a converter, I'm rewriting the code and trying to optimize it in an attempt to help me learn.
A little background
In my original VBScript, I connect to a remote server once using this code:
Set objSWbemLocator = CreateObject("WbemScripting.SWbemLocator")
Set objSWbemServices = objSWbemLocator.ConnectServer(strComputer, "root\cimv2", strUserName, strPassword)
objSWbemServices.Security_.ImpersonationLevel = wbemImpersonationLevelImpersonate
Then I loop through a list of printers I'm looking for and call a function that has the following code:
Set colPorts = objConnection.ExecQuery("SELECT * FROM Win32_Printer WHERE Name = '" & strPrinter & "'")
If colPorts.Count = 0 Then
Set objPort = objConnection.Get("Win32_TCPIPPrinterPort").SpawnInstance_
After the instance is spawned, I add the properties I want to a Dictionary object that has a arbitrary string value with the printer I'm searching for as the key and the property as the value. So, by the time I disconnect from the server, I have a single dictionary object with all the printers I need to work with from that server (I also do the same thing with the ports).
With C#, it doesn't look I will need to use a dictionary because I can use the ManagementObjectSearcher to return a ManagementObjectCollection. Then, if I understand this correctly, I should be able to obtain the properties I need for the specific printer I want from a single ManagementObject or drill down to a PropertyData. With me so far?
The problem/opportunity
Because I'm returning the entire collection, I thought it would be more efficient for me to use LINQ to find the specific printer I need to work with instead of looping through the entire collection. Then, once I have the ManagementObject from LINQ, I could either assign the PropertyData to a variable for later use (assuming that's possible) or loop through the PropertyData to view the contents (mostly for debugging).
I've tried the latter with the following code without any luck:
var printer = from ManagementObject x in mocPrinters
where x.Properties["Name"].Value.ToString() == "MyHP"
select x;
foreach (PropertyData p in printer)
{
MessageBox.Show(string.format("{0}: {1}", p.Name, p.Value);
}
The code above hasn't worked because, I'm assuming, my printer isn't of type PropertyData.
Other helpful info
I thought that querying with LINQ after returning the entire collection would be faster than querying with WMI/WQLs SELECT * FROM Win32_Printer WHERE Name = 'MyHP'
, but if someone has tested this out and knows that the performance difference is negligible, I'm content using WMI/WQL (I'm not quite savvy enough as a programmer to test those things yet).
If anyone has any pointers, I would appreciate it. Thanks...
Upvotes: 3
Views: 7271
Reputation: 40818
Currently you have a collection of ManagementObject
s and you need a collection of PropertyData
.
I think you mean something like this:
var printers = from ManagementObject x in mocPrinters
where x.Properties["Name"].Value.ToString() == "MyHP"
select x;
foreach (PropertyData p in printers.First().Properties)
{
MessageBox.Show(string.format("{0}: {1}", p.Name, p.Value);
}
My experience from using WMI for other tasks is that it is faster to execute when you include filtering in the query. LINQ is not as much about computational efficiency, and more about expressiveness.
The fastest way to access the properties would be to build the WMI path directly. In the case of printers, it seems like the DeviceID
used in the path is the Name. So you can get the object using:
var printer = new ManagementObject("Win32Printer.DeviceID=\"MyHP\"");
Of course, this is for a printer on the local system, but it is relatively easy to build the path for a remote machine as well.
Upvotes: 2