Check If Property Exists On Object C# - c#

I am using a wmi call to get some info shown below
var queryObj = new ObjectQuery("SELECT * FROM Win32_Processor");
var vmSearcher = new ManagementObjectSearcher(queryObj);
foreach (ManagementObject MO in vmSearcher.Get())
{
if (MO.GetType().GetProperty("AddressWidth") != null)
{
Value = MO["AddressWidth"].ToString();
}
//TRY TO FORCE TO NOT EXIST TO TEST..IS THIS THE WAY TO FORCE A
//PROPERTY OUT??
MO["CurrentClockSpeed"] = null;
if (MO.GetType().GetProperty("CurrentClockSpeed") != null)
{
Value2 = MO["CurrentClockSpeed"].ToString();
}
}
The problem is some machines have some properties and others have other properties
How do I check if a property exists or not on a machine?
What I have isn't working
What I ultimately want is to simply print out properties of my choosing (like the on in the code sample) if they exist

public static object TryGetProperty(ManagementObject wmiObj, string propertyName)
{
object retval;
try
{
retval = wmiObj.GetPropertyValue(propertyName);
}
catch (System.Management.ManagementException ex)
{
retval = null;
}
return retval;
}

Related

Issues with ambiguous call

I'm having hard time figuring out what the problem is. I'm trying to make sort of process monitor which loads processes list, ID, username of owner,memory usage and description.. and this error is giving me really big headache.
private void Button1_Click(object sender, EventArgs e)
{
Process[] procList = Process.GetProcesses();
foreach (Process process in procList)
{
// get status
string status = (process.Responding == true ? "Responding" : "Not responding");
// get username and description
string query = "SELECT * FROM Win32_Process WHERE ProcessID = " + process.Id;
ManagementObjectSearcher searcher = new ManagementObjectSearcher(query);
ManagementObjectCollection processList = searcher.Get();
dynamic response = new ExpandoObject();
response.Description = "";
response.Username = "Unknown";
foreach (ManagementObject obj in processList)
{
// get username
string[] argList = new string[] { string.Empty, string.Empty };
int returnValue = Convert.ToInt32(obj.InvokeMethod("GetOwner", argList));
if (returnValue == 0)
response.Username = argList[0];
if (obj["ExecutablePath"] != null)
{
try
{
FileVersionInfo info = FileVersionInfo.GetVersionInfo(obj["ExecutablePath"].ToString());
response.Description = info.FileDescription;
}
catch { }
}
}
// get memory usage
int memsize = 0; // memsize in Megabyte
PerformanceCounter PC = new PerformanceCounter();
PC.CategoryName = "Process";
PC.CounterName = "Working Set - Private";
PC.InstanceName = process.ProcessName;
memsize = Convert.ToInt32(PC.NextValue()) / (int)(1024);
memsize = (memsize / 1024);
PC.Close();
PC.Dispose();
ListViewItem item = new ListViewItem();
item.Text = process.Id.ToString();
item.SubItems.Add(process.ProcessName);
item.SubItems.Add(status);
item.SubItems.Add(response.Username);
item.SubItems.Add(memsize.ToString() + " MB");
item.SubItems.Add(response.Description);
listView1.Items.Add(item);
}
}
When i try debugging the program, it outputs few of them without any problem, (see here -> https://i.imgur.com/D4ftBgb.png) and then error shows up -> https://i.imgur.com/m1R90hz.png
Because you use dynamic, method overload resolution is delayed until runtime. You have a null response.Username or response.Description, so the dynamic runtime doesn't know which overload to call. Compare:
public class Test
{
public static void Main()
{
dynamic bar = null;
try
{
Foo(bar);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
private static void Foo(string f) { }
private static void Foo(int? o) { }
}
This throws the same exception, because both overloads can accept a null, and there is no further type information present.
To resolve this, either specify the overload explicitly by casting to string:
Foo((string)bar);
Or in your case, SubItems.Add((string)response.Username).
Or simply don't use dynamic to stuff your variables in, but keep them both declared as separate variables: string description = "", username = "".
The type of both your response.Username and response.Description is dynamic. The ListViewSubItemCollection.Add() can't decide which overload to use, therefore, you need to convert them to string.
Try the following:
string username = Convert.ToString(response.Username);
string description = Convert.ToString(response.Description);
ListViewItem item = new ListViewItem();
item.Text = process.Id.ToString();
item.SubItems.Add(process.ProcessName);
item.SubItems.Add(status);
item.SubItems.Add(username);
item.SubItems.Add(memsize.ToString() + " MB");
item.SubItems.Add(description);
listView1.Items.Add(item);
The best long term solution is to remove your use of dynamic and use an explicit class with Description and Username properties.
The most direct fix is to change:
response.Description = info.FileDescription;
to:
response.Description = info.FileDescription ?? "";
Why is that necessary (the ?? "")? It will allows the overload resolution to work correctly since Description will never be null. The reason why it doesn't work when null is that a null property of an ExpandoObject has no type associated with it. This is different to a normal class whereby the compiler knows that the type of the property is string.

Npgsql locks thread indefinitely in async environment

I'm struggling to find an answer to a problem I've been experiencing with C#'s popular Postgres library, Npgsql. I'm not sure if it's wholly a problem with Npgsql or not, though I suspect it is because my code is very straight forward. The issue I'm seeing is: when I call an async method on Npgsql sometimes, not all the time, the thread becomes locked. This issue occurs randomly from what I can tell. The result, being that I'm running in a Microsoft Orleans environment (which may be relevant to finding the solution), is that the thread locks indefinitely, thus making one of Orleans' worker threads unable to process work. As I make more Npgsql calls, these locked threads stack up and eventually the Orleans system is choked by thread exhaustion.
So I'm really at a loss for what the problem could be, but because the locking always happens in the same method, and because it appears to be happening in some subroutine of Npgsql, I think it's fair to investigate Npgsql further.
Here's my code which is used in an Orleans storage provider (special class which handles the system's persistence layer.)
var sql = $"SELECT * FROM objects WHERE id = #id";
using (var connection = new NpgsqlConnection(connectionString))
using (var cmd = new NpgsqlCommand(sql, connection))
{
try
{
await connection.OpenAsync();
cmd.Parameters.AddWithValue("id", id);
using(var reader = await connection.ExecuteReaderAsync(cmd))
{
if (reader.HasRows)
{
var objects = await ProtobufSQL.DataReaderToType(modelType, reader);
var data = objects[0];
state.Data = data;
}
}
catch (Exception e)
{
Log.Error(1, e.Message, e);
}
}
This is the source for the ProtobufSQL class:
public class ProtobufSQL
{
public static List<Tuple<string, object>> FlattenToSQLColumns(IMessage message, MessageDescriptor descriptor, string prefix = null)
{
var fields = descriptor.Fields.InDeclarationOrder();
var columns = new List<Tuple<string, object>>();
for (var i = 0; i < fields.Count; i++)
{
var field = fields[i];
var columnName = field.Name.ToLower();
if (field.Name == "id")
{
ByteString bytes = (ByteString)field.Accessor.GetValue(message);
var uuid = new Guid(bytes.ToByteArray());
columns.Add(new Tuple<string, object>("id", uuid));
}
else if (field.FieldType == FieldType.Message)
{
var embeddedDescriptor = field.MessageType;
var embeddedMessage = field.Accessor.GetValue(message);
if (field.IsRepeated)
{
throw new Exception("Repeated complex types are not supported, create a foreign key reference in a new object instead.");
}
else
{
columns.AddRange(FlattenToSQLColumns((IMessage)embeddedMessage, embeddedDescriptor, $"{columnName}."));
}
}
else if (field.FieldType == FieldType.Group)
{
throw new Exception("Groups are not supported by ProtobufSQL.");
}
else
{
var columnValue = field.Accessor.GetValue(message);
var key = prefix + columnName;
if (field.IsRepeated)
{
var enumerableColumnValue = columnValue as IEnumerable;
Type listTypeOf = enumerableColumnValue.GetType().GetGenericArguments()[0];
Type listType = typeof(List<>).MakeGenericType(listTypeOf);
dynamic valueList = Activator.CreateInstance(listType);
foreach (var item in enumerableColumnValue)
{
valueList.Add((dynamic)item);
}
columns.Add(new Tuple<string, object>(key, valueList.ToArray()));
}
else
{
columns.Add(new Tuple<string, object>(key, columnValue));
}
}
}
return columns;
}
public static async Task<IMessage[]> DataReaderToType(Type type, DbDataReader reader)
{
var descriptor = (MessageDescriptor)type.GetProperty("Descriptor").GetValue(null);
IList<IMessage> objects = new List<IMessage>();
while (await reader.ReadAsync())
{
var obj = Activator.CreateInstance(type);
TraverseDbRow(reader, descriptor, obj);
objects.Add((IMessage)obj);
}
return objects.ToArray();
}
private static void TraverseDbRow(DbDataReader reader, MessageDescriptor descriptor, object obj, string prefix = null)
{
var fields = descriptor.Fields.InFieldNumberOrder();
for (var i = 0; i < fields.Count; i++)
{
var field = fields[i];
if (field.FieldType == FieldType.Message)
{
if (field.IsRepeated)
{
// Repeated embedded types will be broken out into a separate table,
// so there's no need to handle them here.
}
else if (field.IsMap)
{
throw new Exception("Maps are not yet supported by ProtobufSQL.");
}
else
{
var embeddedDescriptor = field.MessageType;
var embeddedObj = Activator.CreateInstance(embeddedDescriptor.ClrType);
TraverseDbRow(reader, embeddedDescriptor, embeddedObj, $"{prefix}{field.Name}.");
}
}
else if (field.FieldType == FieldType.Group)
{
throw new Exception("Groups are not supported by ProtobufSQL.");
}
else
{
var columnName = prefix + field.Name;
try
{
var columnValue = reader[columnName];
var propertyInfo = obj.GetType().GetProperty(field.Name, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
if (field.Name == "id")
{
var guid = (Guid)columnValue;
ByteString bytes = ByteString.CopyFrom(guid.ToByteArray());
propertyInfo.SetValue(obj, bytes);
}
else if (field.IsRepeated)
{
var repeated = propertyInfo.GetValue(obj);
var addRange = repeated.GetType().GetMethod("AddRange");
addRange.Invoke(repeated, new object[] { columnValue });
}
else if (field.IsMap)
{
throw new Exception("Maps are not yet supported by ProtobufSQL.");
}
else
{
propertyInfo.SetValue(obj, Convert.ChangeType(columnValue, propertyInfo.PropertyType));
}
}
catch (IndexOutOfRangeException e)
{
// columnName was not present in the response
}
}
}
}
}
I also have this screenshot of the thread's stack when it got locked:
I'm really unsure what to make of all this. Hopefully someone is out there with a bit of knowledge that can help me proceed! Thanks.

C# Outlook AddIn 2010 cannot read UserDefinedProperty

I have defined four custom user properties and i can not access to the in order to get their data, custom properties are present in outlook appointment but i can get to them :
My c# code below :
Outlook.ItemProperties itemProp = appointmentItem.ItemProperties;
foreach (Outlook.ItemProperty userprop in itemProp)
{
if (userprop.IsUserProperty)
{
MessageBox.Show(userprop.Name + "\t" + userprop.Value);
}
}
I have used an api(JWebServices) that creates appointment event into Outlook(2007 my version), in my code below i have created some CustomProperties, called in C# Addin Outlook UserPropertie.
I still can get the value of custom users properties that i have defined from the java side
PropertyName myRdvTypePropertyName = new PropertyName("RdvType", StandardPropertySet.PUBLIC_STRINGS);
ExtendedProperty myRdvTypeExtendedProperty = new ExtendedProperty(myRdvTypePropertyName, event.getTyperdv());
appointment.getExtendedProperties().add(myRdvTypeExtendedProperty);
PropertyName myRdvEmplacementPropertyName = new PropertyName("RdvEmplacement", StandardPropertySet.PUBLIC_STRINGS);
ExtendedProperty myRdvEmplacementExtendedProperty = new ExtendedProperty(myRdvEmplacementPropertyName, event.getLieu());
appointment.getExtendedProperties().add(myRdvEmplacementExtendedProperty);
PropertyName myRdvAdressePropertyName = new PropertyName("RdvAdresse", StandardPropertySet.PUBLIC_STRINGS);
ExtendedProperty myRdvAdresseExtendedProperty = new ExtendedProperty(myRdvAdressePropertyName, event.getEvent_location());
appointment.getExtendedProperties().add(myRdvAdresseExtendedProperty);
To be sure the custom user properties are created, i use Outlook SPY
the screenshot below:
the code below in the FormRegionShowing :
if (appointmentItem.UserProperties["RdvType"] != null)
{
this.TypeRdvComboBox.SelectedItem = appointmentItem.UserProperties["RdvType"].Value;
}
if (appointmentItem.UserProperties["RdvEmplacement"] != null)
{
this.emplacementRdvComboBox.SelectedItem = appointmentItem.UserProperties["RdvEmplacement"].Value;
}
if (appointmentItem.UserProperties["RdvAdresse"] != null)
{
this.adresseTextBox.Text = (string)appointmentItem.UserProperties["RdvAdresse"].Value;
}
Thanks for the inspiration, this works:
Outlook.MailItem mItem = (Outlook.MailItem)item;
string udpName = "";
string udpValueString = "";
Debug.Print(" mItem.UserProperties.Count: " + mItem.UserProperties.Count);
for (int i = 1; i <= mItem.UserProperties.Count; i++) {
udpName = mItem.UserProperties[i].Name;
var udpValue = mItem.UserProperties[i].Value;
udpValueString = udpValue.ToString();
Debug.Print(i + ": " + udpName + ": " + udpValueString);
}
Try using the UserProperties property and UserProperties class instead. Here is what MSDN states:
If you use UserProperties.Find to look for a custom property and the call succeeds, it will return a UserProperty object. If it fails, it will return Null. If you use UserProperties.Find to look for a built-in property, specify False for the Custom parameter. If the call succeeds, it will return the property as a UserProperty object. If the call fails, it will return Null. If you specify True for Custom, the call will not find the built-in property and will return Null.
using System.Runtime.InteropServices;
// ...
private void ShowUserProperties(Outlook.MailItem mail)
{
Outlook.UserProperties mailUserProperties = null;
Outlook.UserProperty mailUserProperty = null;
StringBuilder builder = new StringBuilder();
mailUserProperties = mail.UserProperties;
try
{
for (int i = 1; i < = mailUserProperties.Count; i++)
{
mailUserProperty = mailUserProperties[i];
if (mailUserProperty != null)
{
builder.AppendFormat("Name: {0} \tValue: {1} \n\r",
mailUserProperty.Name, mailUserProperty.Value);
Marshal.ReleaseComObject(mailUserProperty);
mailUserProperty = null;
}
}
if (builder.Length > 0)
{
System.Windows.Forms.MessageBox.Show(builder.ToString(),
"The UserProperties collection");
}
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
}
finally
{
if (mailUserProperties != null)
Marshal.ReleaseComObject(mailUserProperties);
}
}
Read more about that in the How To: Get Outlook e-mail item’s custom properties – C# and VB.NET samples article.

How do I retrieve the default icon for any given file type in Windows?

How do I get the icon that Windows uses by default for a specified file type?
Default icons for a file type irrespective of whether you happen to have one of these types of files handy, are defined in the Window's Registry under
HKEY_CLASSES_ROOT\ type \DefaultIcon(Default)
...but why tinker with that when there is a nice c# code sample here by VirtualBlackFox in his answer to How do I get common file type icons in C#?
Try this
public static Hashtable GetTypeAndIcon()
{
try
{
RegistryKey icoRoot = Registry.ClassesRoot;
string[] keyNames = icoRoot.GetSubKeyNames();
Hashtable iconsInfo = new Hashtable();
foreach (string keyName in keyNames)
{
if (String.IsNullOrEmpty(keyName)) continue;
int indexOfPoint = keyName.IndexOf(".");
if (indexOfPoint != 0) continue;
RegistryKey icoFileType = icoRoot.OpenSubKey(keyName);
if (icoFileType == null) continue;
object defaultValue = icoFileType.GetValue("");
if (defaultValue == null) continue;
string defaultIcon = defaultValue.ToString() + "\\DefaultIcon";
RegistryKey icoFileIcon = icoRoot.OpenSubKey(defaultIcon);
if (icoFileIcon != null)
{
object value = icoFileIcon.GetValue("");
if (value != null)
{
string fileParam = value.ToString().Replace("\"", "");
iconsInfo.Add(keyName, fileParam);
}
icoFileIcon.Close();
}
icoFileType.Close();
}
icoRoot.Close();
return iconsInfo;
}
catch (Exception exc)
{
throw exc;
}
}

Create a new Hyper-V VM (using WMI) with specific hardware

I'm wanting to create a new Hyper-V VM with a determined amount of RAM, network card, number of processor cores, and attach a VHD file to the IDE controller.
The problem is that the Msvm_ResourceAllocationSettingData is not very easy to work with. The code I'm using doesn't work (this is code to attach a VHD to an existing VM, however I would also like to use it when creating a new VHD too).
public void AttachVhd(IdeChannel ideChannel, String vhdPath) {
// Get VirtualSystemSettingData
ManagementObject vssd = this.GetVirtualSystemSettingData();
// Get the IDE Controller
ManagementObject ideController = this.GetResourceAllocationSettingData(ResourceType.IdeController, ResourceSubType.IdeController);
// Create synthetic disk:
ManagementObject syntheticDiskRasd = this.GetResourceAllocationSettingData(ResourceType.Disk, ResourceSubType.DiskSynthetic);
syntheticDiskRasd["Parent"] = ideController.Path;
syntheticDiskRasd["Address"] = ideChannel == IdeChannel.Primary ? "0" : "1";
this.AddVirtualSystemResources(syntheticDiskRasd);
// Attach it
ManagementObject vhdRasd = this.GetResourceAllocationSettingData(ResourceType.StorageExtent, ResourceSubType.Vhd); ;
vhdRasd["Parent"] = syntheticDiskRasd.Path;
vhdRasd["Connection"] = new String[] { vhdPath };
this.AddVirtualSystemResources( vhdRasd );
// Cleanup
vhdRasd.Dispose();
syntheticDiskRasd.Dispose();
ideController.Dispose();
vssd.Dispose();
}
private ManagementObject GetResourceAllocationSettingData(ResourceType resourceType, ResourceSubType resourceSubType)
{
String desiredSubType = ResourceSubTypeStrings.GetString(resourceSubType); // Scout.Common.Extensions.GetDescription( resourceType );
using(ManagementObjectCollection settingsDatas = _vm.GetRelated("Msvm_VirtualSystemSettingData"))
foreach(ManagementObject settingData in settingsDatas)
{
using(ManagementObjectCollection rasds = settingData.GetRelated("Msvm_ResourceAllocationSettingData"))
foreach(ManagementObject rasd in rasds)
{
ResourceType rasdResourceType = (ResourceType)(UInt16)rasd["ResourceType"];
String rasdResourceSubType = (String)rasd["ResourceSubType"];
String rasdOtherType = (String)rasd["OtherResourceType"];
if( rasdResourceType == resourceType && rasdResourceSubType == desiredSubType )
{
return rasd;
}
}
}
return null;
}
private void AddVirtualSystemResources(ManagementObject rasd)
{
using (ManagementObject vmService = HyperV.GetManagementService())
{
ManagementBaseObject inParams = vmService.GetMethodParameters("AddVirtualSystemResources");
inParams["TargetSystem"] = _vm;
inParams["ResourceSettingsData"] = rasd.GetText(TextFormat.CimDtd20);
ManagementBaseObject outParams = vmService.InvokeMethod("AddVirtualSystemResources", inParams, options: null);
String[] addedResources = (String[])outParams["NewResources"];
OperationReturnCode returnValue = (OperationReturnCode)(UInt32)outParams["ReturnValue"];
if (returnValue == OperationReturnCode.JobStarted)
{
String jobPath = (String)outParams["Job"];
HyperV.MonitorJob(jobPath);
}
else if (returnValue == OperationReturnCode.Completed)
{
}
else
{
throw new ApplicationException( returnValue.ToString() );
}
}
}
Rather than find your problem, can I point you to an example that works?
See WmiCalls.DeployVirtualMachine in my Apache CloudStack Hyper-V plugin
Post a comment if you need additional detail, and I will update the answer.

Categories