Issues with ambiguous call - c#

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.

Related

Check If Property Exists On Object 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;
}

What is the relationship between Process.GetProcesses(); and what is shown in Task Manager?

I'm trying to do something which should be (and probably is) very simply. I want a user to be able to define a process (Almost certainly taken from Task Manager) and then my application will perform differently depending on which processes are running.
I've been playing with Process.GetProcesses() to get this information, but I'm struggling to understand the data I'm getting and how it relates to what Task Manager displays.
What I really want is a list of process names which are identical to the "Name" field in Task Manager. I can get this using Path.GetFileName(theprocess.MainModule.FileName); but I get a lot of Exceptions when enumerating certain processes. This appears (from Googling) to be expected especially in cross 64bit/32bit platforms, and while I can easily trap and ignore these it becomes an exceptionally slow operation.
So, I'm hoping to use something simply like process.ProcessName. At first glance this seems to be identical to Task Manager, but there are the odd one or two tasks that it pulls back which don't show up in Task Manager.
Should I be doing something else, or should process.ProcessName be sufficient?
By the way, I'm only interesting in enumerating processes for the current user/session.
Here's one of my code examples:
foreach (theprocess in processList)
{
try
{
string fileName = theprocess.MainModule.FileName;
currentProcessList.Add(fileName.ToLower());
}
catch (Exception e)
{
}
}
I have never used your method, but in my application I use WMI to iterate over processes as follows:
List<ManagementObject> processInfo = processWmi.CreateRequest("SELECT * FROM Win32_Process");
processWmi is a class I use for all of my WMI queries that has extra functionality to kill the query if it is hanging (which WMI seems to do on some servers). The heart of this class is shown below.
private static string _query;
private static string _scope;
private static List<ManagementObject> _data;
private static bool _queryComplete;
private int _timeout = 300;
private static readonly object Locker = new Object();
public List<ManagementObject> CreateRequest(string query, bool eatErrors = false, string scope = null)
{
try
{
lock (Locker)
{
_queryComplete = false;
AscertainObject.ErrorHandler.WriteToLog("Running WMI Query: " + query + " Timeout:" + _timeout, true);
_query = query;
_scope = scope;
Thread serviceThread = new Thread(RunQuery) { Priority = ThreadPriority.Lowest, IsBackground = true };
serviceThread.Start();
int timeLeft = _timeout * 10;
while (timeLeft > 0)
{
if (_queryComplete)
return _data;
timeLeft--;
Thread.Sleep(100);
}
if (eatErrors == false)
AscertainObject.ErrorHandler.WriteToLog("WMI query timeout: " + query, true, "");
serviceThread.Abort();
}
}
catch (Exception ex)
{
if (eatErrors == false)
AscertainObject.ErrorHandler.WriteToLog("Error Running WMI Query", true, ex.ToString());
}
return null;
}
public void SetRequestTimeout(int timeoutSeconds)
{
_timeout = timeoutSeconds;
AscertainObject.ErrorHandler.WriteToLog("WMI query timeout changed to " + timeoutSeconds + " seconds", true);
}
private void RunQuery()
{
try
{
ManagementObjectSearcher searcher = _scope != null ? new ManagementObjectSearcher(_scope, _query) : new ManagementObjectSearcher(_query);
List<ManagementObject> innerData = searcher.Get().Cast<ManagementObject>().ToList();
_data = innerData;
}
catch (Exception ex)
{
AscertainObject.ErrorHandler.WriteToLog("WMI query failed, may have invalid namespace", true, null, true);
_data = null;
}
_queryComplete = true;
}
You can pull the data you want out of the WMI results as follows (type conversions in place to match my Process class):
foreach (ManagementObject item in processInfo)
{
Process tempProcess = new Process
{
id = Convert.ToInt32((UInt32)item["ProcessID"]),
name = (String)item["Name"],
path = (String)item["ExecutablePath"],
parentID = Convert.ToInt32((UInt32)item["ParentProcessID"]),
handleCount = Convert.ToInt32((UInt32)item["HandleCount"]),
priority = Convert.ToInt16((UInt32)item["Priority"]),
threadCount = Convert.ToInt32((UInt32)item["ThreadCount"]),
workingSetMB = Convert.ToInt64((UInt64)item["WorkingSetSize"]) / 1048576,
peakWorkingSetMB = Convert.ToInt64((UInt32)item["PeakWorkingSetSize"]) / 1024,
pageFileUsageMB = Convert.ToInt64((UInt32)item["PageFileUsage"]) / 1024,
peakPageFileUsage = Convert.ToInt64((UInt32)item["PeakPageFileUsage"]) / 1024
};
try
{
//get owner info
object[] ownerInfo = new object[2];
item.InvokeMethod("GetOwner", ownerInfo);
tempProcess.processOwner = (string)ownerInfo[0];
}
catch
{
}
}
WMI results are usually returned very quickly with little to no overhead on the system. They also act similar to SQL queries where you can filter the results with proper WHERE clauses.
Here is the link to all the info you can get back from Win32_Process:
http://msdn.microsoft.com/en-us/library/aa394372(v=vs.85).aspx

cannot call method with null arguments c#

I have a method with parameters and i want to call it in my global application class, but when i pass null arguments it will give an error. I'm sharing my code please guide me.
Method:
public static async Task getMessage(Controller page,string Email, int? PersonId, int? OrderDetailId, int? TicketDetailId)
{
using (var client = new ImapClient("imap.gmail.com", true))
{
// Connecting
if (client.Connect())
{
// Sign in
if (client.Login("abc#gmail.com", "*****"))
{
var excludeLabels = new string[] { "Processed" };
var senders = new string[] { Email };
// Building the search query
var query = string.Format("X-GM-RAW \"{0} -({1})\"",
string.Join(" OR ", senders.Select(sender => "(from:" + sender + ")")),
string.Join(" OR ", excludeLabels.Select(label => "(label:" + label + ")")));
var messages = client.Folders.Inbox.Search(query, MessageFetchMode.ClientDefault, 1000);
foreach (var msg in messages)
{
// Mark the message as seen
msg.Seen = true;
string plainTextBody = msg.Body.HasText ? msg.Body.Text : "";
string htmlBody = msg.Body.HasHtml ? msg.Body.Html : "";
var time = DateTime.SpecifyKind(msg.Date.HasValue ? msg.Date.Value : DateTime.Now, DateTimeKind.Utc);
if (msg.Attachments.Count() > 0)
{
foreach (var file in msg.Attachments)
{
var folder = Server.MapPath("~/Data/ConversationAttachments");
if (!Directory.Exists(folder))
{
Directory.CreateDirectory(folder);
}
string guid = Guid.NewGuid().ToString();
string webPath = null;
msg.Download(MessageFetchMode.Full);
int posOfDot = file.FileName.LastIndexOf(".");
string fName = Guid.NewGuid().ToString() + file.FileName.Substring(posOfDot);
webPath = "~/Data/ConversationAttachments/" + fName;
file.Save(Server.MapPath("~/Data/ConversationAttachments"), fName);
db.MailSystems.AddOrUpdate(c => c.MESSAGEID, new MailSystem
{
Message = htmlBody,
Date = time,
Attachment = webPath,
EmailType = "IMAP",
Subject = string.IsNullOrEmpty(msg.Subject) ? "RE: Ticket ID " + TicketDetailId.Value.ToString() : msg.Subject,
Sender = Email,
PersonID = PersonId.Value,
TicketDetailId = TicketDetailId.Value,
MESSAGEID = msg.MessageId
});
}
}
await db.SaveChangesAsync();
}
}
}
}
}
Global Application Class:
protected void ThreadFunc()
{
System.Timers.Timer t = new System.Timers.Timer();
t.Elapsed += new System.Timers.ElapsedEventHandler(TimerWorker);
t.Interval = 10000;
t.Enabled = true;
t.AutoReset = true;
t.Start();
}
protected void TimerWorker(object sender, System.Timers.ElapsedEventArgs e)
{
GetMail.getMessage();
}
getMessage method is a static member of static GetMail class. Please guide me how i can solve this issue. I want to start the getMessage method automatically after every 30 seconds.
GetMail.getMessage();
Doesnt work, because there aren't a method with these signature. the parameters can be null (int**?**), but they aren't optional..
Change to:
GetMail.getMessage(null, null, null, null, null);
Or create a new method with no parameters... and then call your method
public static void getMessage()
{
GetMessage(null, null, null, null, null);
}
Or set default values
public static void getMessage(Person page = null, string Email ="", int? PersonId =0, int? OrderDetailId=0, int? TicketDetailId=0) { ... }
It will work... but.. it is a creepy code :-)
Your problem is that your code attempts to call other methods and properties on the nullable types that are passed into your method.
I.e.
PersonId.Value
TicketDetailId.Value
If you want to have nullable arguments in your method signature and be able to pass null values for those arguments, you need to fix your code so it works with those arguments being null.
In short, there's no obvious answer here, you can't pass in null arguments and expect to be able to use their properties and methods without encountering an exception.
Your usual solutions are, pass in types that can't be null:
public void MyMethod(int myValue)
Or do a null check before:
if (myThing == null)
{
return;
}
Or:
if (myThing != null)
{
// Do stuff.
}
Or apply the '??' operator to apply a default value if null:
string myResult = myThing ?? string.Empty;
EDIT
Your other problem is that you're calling the getMessage() method with no parameters. The signature of getMessage looks like:
getMessage(Controller page, string email, int? personId, int? orderDetailId, int? ticketDetailId)
(Note I've lowercased the first letter of your argument names, as per typical C# standards)
You should be passing some parameters when calling it:
getMessage("myPage", "test#hotmail.com", 2, 37, 92);
You need to understand a lot more about the very basics of C# and Object Oriented programming in general. Try reading some introductory books on C# development.

How to get motherboard ID without receiving empty strings?

I tried many things:
//public static string GetMotherBoardID()
//{
// string mbInfo = String.Empty;
// //Get motherboard's serial number
// ManagementObjectSearcher mbs = new ManagementObjectSearcher("Select * From Win32_BaseBoard");
// foreach (ManagementObject mo in mbs.Get())
// mbInfo += mo["SerialNumber"].ToString();
// return mbInfo;
//}
//public static string GetMotherBoardID()
//{
// string mbInfo = String.Empty;
// ManagementScope scope = new ManagementScope("\\\\" + Environment.MachineName + "\\root\\cimv2");
// scope.Connect();
// ManagementObject wmiClass = new ManagementObject(scope, new ManagementPath("Win32_BaseBoard.Tag=\"Base Board\""), new ObjectGetOptions());
// foreach (PropertyData propData in wmiClass.Properties)
// {
// if (propData.Name == "SerialNumber")
// mbInfo = String.Format("{0,-25}{1}", propData.Name, Convert.ToString(propData.Value));
// }
// return mbInfo;
//}
public static string GetMotherBoardID()
{
string mbInfo = String.Empty;
ManagementObjectSearcher mbs = new ManagementObjectSearcher("Select * From Win32_BaseBoard");
ManagementObjectCollection moc = mbs.Get();
ManagementObjectCollection.ManagementObjectEnumerator itr = moc.GetEnumerator();
itr.MoveNext();
mbInfo = itr.Current.Properties["SerialNumber"].Value.ToString();
var enumerator = itr.Current.Properties.GetEnumerator();
if (string.IsNullOrEmpty(mbInfo))
mbInfo = "0";
return mbInfo;
}
This all gives empty string on my PC, but the correct ID on the laptop.
Some other person also reporting on two PCs is empty motherboard ID.
The result of:
public static string GetMotherBoardID()
{
string mbInfo = String.Empty;
ManagementObjectSearcher mbs = new ManagementObjectSearcher("Select * From Win32_BaseBoard");
ManagementObjectCollection moc = mbs.Get();
ManagementObjectCollection.ManagementObjectEnumerator itr = moc.GetEnumerator();
itr.MoveNext();
mbInfo = itr.Current.Properties["SerialNumber"].Value.ToString();
var enumerator = itr.Current.Properties.GetEnumerator();
string properties = "";
while (enumerator.MoveNext())
{
properties += "[" + enumerator.Current.Name + "][" + (enumerator.Current.Value != null ? enumerator.Current.Value.ToString() : "NULL") + "]\n";
}
if (string.IsNullOrEmpty(mbInfo))
mbInfo = "0";
return mbInfo;
}
[Caption][Основная плата]
[ConfigOptions][NULL]
[CreationClassName][Win32_BaseBoard]
[Depth][NULL]
[Description][Основная плата]
[Height][NULL]
[HostingBoard][True]
[HotSwappable][False]
[InstallDate][NULL]
[Manufacturer][Gigabyte Technology Co., Ltd.]
[Model][NULL]
[Name][Основная плата]
[OtherIdentifyingInfo][NULL]
[PartNumber][NULL]
[PoweredOn][True]
[Product][H55M-S2H]
[Removable][False]
[Replaceable][True]
[RequirementsDescription][NULL]
[RequiresDaughterBoard][False]
[SerialNumber][ ]
[SKU][NULL]
[SlotLayout][NULL]
[SpecialRequirements][NULL]
[Status][OK]
[Tag][Base Board]
[Version][x.x]
[Weight][NULL]
[Width][NULL]
Maybe c# is bad for retrieving such things?
I hope for solution on C/C++ or working solution on C#
Some motherboards simply don't have ID. It set to empty string.
So, if someone need to use motherboard unique thing for licensing purposes they should receive motherboard UUID.
Personally, I'd recommend using this particular Open Source hardware monitor library (you'll need the source). You can use it for hardware identification. Open Hardware Monitor
There is also a NuGet package called DeviceID. However, you will need to include their DLL with your package, but is a great fast, simple solution.
Here a usage example:
/* Depends on https://www.nuget.org/packages/DeviceId/ Install-Package DeviceId - Version 5.2.0*/
/* Using AddMacAddress(true, true) to exclude both virtual and wireless network adapters. */
readonly string MachineSupportID = new DeviceIdBuilder()
.AddMacAddress(true, true)
.AddMotherboardSerialNumber()
.AddProcessorId()
.AddSystemDriveSerialNumber()
.ToString();
May the force be with you.

Retrieving user attributes from Active Directory using LDAP - JAVA

EDIT: I've posted the solution below.
I know you don't like these type of questions, but i've been struggling with this issue for half a day now.
I've written a C# code that fetches user attributes from our Active Directory using LDAP, the code works well.
The code is as follows:
DirectoryEntry dirEnt = new DirectoryEntry("LDAP://dc=dom,dc=int");
DirectorySearcher adSearch = new DirectorySearcher(dirEnt);
adSearch.SearchScope = SearchScope.Subtree;
adSearch.PageSize = 10000;
adSearch.Filter = "(&(objectClass=user))";
SearchResultCollection sColl = adSearch.FindAll();
foreach (SearchResult sResult in sColl)
{
string sConn = sResult.Properties["distinguishedName"][0].ToString();
DirectoryEntry dirEnt2 = new DirectoryEntry("LDAP://" + sConn);
...
// dirEnt2 contains ALL attributes for the user
}
I'm trying to port this code to Java, but it seems like that the technique I used in C# does not work too well in Java.
Using the following code
DirContext context;
ArrayList<String> nList = new ArrayList<String>();
Hashtable env = new Hashtable();
String username = ...;
String password = ...;
try {
env.put(Context.SECURITY_PRINCIPAL, username);
env.put(Context.SECURITY_CREDENTIALS, password);
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, ldapUri);
try {
context = new InitialDirContext(env);
} catch (NamingException e) {
throw new RuntimeException(e);
}
SearchControls ctrl = new SearchControls();
ctrl.setSearchScope(SearchControls.SUBTREE_SCOPE);
NamingEnumeration enumeration = context.search("", "(objectClass=user)",
ctrl);
while (enumeration.hasMore()) {
SearchResult result = (SearchResult) enumeration.next();
Attributes attribs = result.getAttributes();
NamingEnumeration values = ((BasicAttribute)
attribs.get("distinguishedName")).getAll();
while (values.hasMore()) {
nList.add(values.next().toString());
}
}
} catch (NamingException e) {
e.printStackTrace();
}
for (String sVar : nList ){
Hashtable env2 = new Hashtable();
env2.put(Context.SECURITY_PRINCIPAL, username);
env2.put(Context.SECURITY_CREDENTIALS, password);
env2.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.ldap.LdapCtxFactory");
env2.put(Context.PROVIDER_URL, "ldap://DOM/" + sVar);
Attributes attrs = null;
try {
context = new InitialDirContext(env2);
attrs = context.getAttributes(sVar);
} catch (NamingException e) {
System.out.println(e.toString());
continue;
}
System.out.println(attrs.toString());
}
Yields that attrs only contains BASIC attributes regarding the user (such as samaccountname, displayname, etc)
and no 'email', 'telephone' or any other similar attributes.
Any help on the issue is blessed!
Here's the solution, sorry for the messy code/formatting
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.*;
import javax.naming.ldap.*;
public class UserFetch {
public static void main(String[] args) {
try{
// Activate paged results
byte[] cookie = null;
int count=0;
int total;
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.REFERRAL, "follow");
env.put(Context.SECURITY_AUTHENTICATION, "Simple");
env.put(Context.SECURITY_PRINCIPAL, "USERNAME#DOM.COM");
env.put(Context.SECURITY_CREDENTIALS, "PASSWORD");
env.put(Context.PROVIDER_URL, "ldap://DOM.COM:389");
LdapContext ctx = new InitialLdapContext(env, null);
ctx.setRequestControls(new Control[]{
new PagedResultsControl(10000, Control.CRITICAL) });
do {
// Perform the search
NamingEnumeration results =
ctx.search("dc=DOM,dc=COM", "(&(objectclass=user)(employeeNumber=*))", getSimpleSearchControls());
// Iterate over a batch of search results
while (results != null && results.hasMore()) {
// Display an entry
SearchResult entry = (SearchResult)results.next();
Attributes attrs = entry.getAttributes ();
System.out.println(attrs.get("SAMAccountName")); // Username
System.out.println("Firstname: " +
attrs.get("givenname")); // firstname
System.out.println("Lastname: " + attrs.get("sn")); // lastname
System.out.println("EmployeeID " + attrs.get("employeeID"));
System.out.println("EmployeeNumber: " +
attrs.get("employeeNumber"));
// Handle the entry's response controls (if any)
}
// Examine the paged results control response
Control[] controls = ctx.getResponseControls();
if (controls != null) {
for (int i = 0; i < controls.length; i++) {
if (controls[i] instanceof PagedResultsResponseControl) {
PagedResultsResponseControl prrc =
(PagedResultsResponseControl)controls[i];
total = prrc.getResultSize();
cookie = prrc.getCookie();
} else {
// Handle other response controls (if any)
}
}
}
// Re-activate paged results
ctx.setRequestControls(new Control[]{
new PagedResultsControl(10000, cookie, Control.CRITICAL) });
} while (cookie != null);
} catch (Exception e) {
e.printStackTrace();
}
}
public static SearchControls getSimpleSearchControls() {
SearchControls searchControls = new SearchControls();
searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
searchControls.setTimeLimit(30000);
String[] attrIDs =
{ "SAMAccountName", "sn", "givenname", "employeeID",
"employeeNumber" };
searchControls.setReturningAttributes(attrIDs);
return searchControls;
}
}
Try setting the returned attributes on your SearchControls
ctrl.setReturningAttributes(new String[] {"email", "telephone"});

Categories