Obtain the real size of a screen - c#

Is it possible to get the real screen size in cm not in pixels ? ie i need to know the size of the sreen not its resolution.
I need this if it's possible in a windows application.

All information about screen (from manufacturer) is in registry HKLM\SYSTEM\CurrentControlSet\Enum\DISPLAY. The size of the screen is encoded, and hard to find, but it's possible.
For more information, search on the web for : EDID ("Extended display identification data") ( http://en.wikipedia.org/wiki/Extended_display_identification_data , the bytes for the size are #21 and #22)
Here the code I use to have the size (and more information, but I cleaned the code to have only the size) :
// Open the Display Reg-Key
RegistryKey displayRegistry = Registry.LocalMachine;
Boolean isFailed = false;
try
{
displayRegistry = Registry.LocalMachine.OpenSubKey(#"SYSTEM\CurrentControlSet\Enum\DISPLAY");
}
catch
{
isFailed = true;
}
if (!isFailed & (displayRegistry != null))
{
// Get all MonitorIDss
foreach (String monitorID in displayRegistry.GetSubKeyNames())
{
if (monitorID == name)
{
RegistryKey monitorIDRegistry = displayRegistry.OpenSubKey(monitorID);
if (monitorIDRegistry != null)
{
// Get all Plug&Play ID's
foreach (String subname in monitorIDRegistry.GetSubKeyNames())
{
RegistryKey pnpID = monitorIDRegistry.OpenSubKey(subname);
if (pnpID != null)
{
String[] subkeys = pnpID.GetSubKeyNames();
// Check if Monitor is active
if (subkeys.Contains("Control"))
{
if (subkeys.Contains("Device Parameters"))
{
RegistryKey devParam = pnpID.OpenSubKey("Device Parameters");
Int16 sizeH = 0;
Int16 sizeV = 0;
// Get the EDID code
byte[] edidObj = devParam.GetValue("EDID", null) as byte[];
if (edidObj != null)
{
sizeH = Convert.ToInt16(Encoding.Default.GetString(edidObj, 0x15, 1)[0]);
sizeV = Convert.ToInt16(Encoding.Default.GetString(edidObj, 0x16, 1)[0]);
}
}
}
}
}
}
}
}
}
The size is in cm (it's integer only).
You can have with this physical ratio and diagonal :
private static String GetRatio(Double MaxSizeH, Double MaxSizeV)
{
if (MaxSizeV == 0)
{
return "undefined";
}
Double ratio = MaxSizeH / MaxSizeV;
String strRatio = "4/3";
Double ecartRatio = Math.Abs(ratio - (4 / (Double)3));
if (Math.Abs(ratio - (16 / (Double)10)) < ecartRatio)
{
ecartRatio = Math.Abs(ratio - (16 / (Double)10));
strRatio = "16/10";
}
if (Math.Abs(ratio - (16 / (Double)9)) < ecartRatio)
{
ecartRatio = Math.Abs(ratio - (16 / (Double)9));
strRatio = "16/9";
}
return strRatio;
}
// diagonal in inch
private static Double GetDiagonale(Double MaxSizeH, Double MaxSizeV)
{
return 0.3937 * Math.Sqrt(MaxSizeH * MaxSizeH + MaxSizeV * MaxSizeV);
}
Edit: How to have monitor name (all connected monitors) :
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct DISPLAY_DEVICE
{
[MarshalAs(UnmanagedType.U4)]
public int cb;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string DeviceName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string DeviceString;
[MarshalAs(UnmanagedType.U4)]
public DisplayDeviceStateFlags StateFlags;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string DeviceID;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string DeviceKey;
}
[Flags]
public enum DisplayDeviceStateFlags : int
{
/// <summary>The device is part of the desktop.</summary>
AttachedToDesktop = 0x1,
MultiDriver = 0x2,
/// <summary>The device is part of the desktop.</summary>
PrimaryDevice = 0x4,
/// <summary>Represents a pseudo device used to mirror application drawing for remoting or other purposes.</summary>
MirroringDriver = 0x8,
/// <summary>The device is VGA compatible.</summary>
VGACompatible = 0x10,
/// <summary>The device is removable; it cannot be the primary display.</summary>
Removable = 0x20,
/// <summary>The device has more display modes than its output devices support.</summary>
ModesPruned = 0x8000000,
Remote = 0x4000000,
Disconnect = 0x2000000
}
[DllImport("User32.dll")]
public static extern int EnumDisplayDevices(string lpDevice, int iDevNum, ref DISPLAY_DEVICE lpDisplayDevice, int dwFlags);
private static List<NativeMethods.DISPLAY_DEVICE> GetAllDevice()
{
List<NativeMethods.DISPLAY_DEVICE> devices = new List<NativeMethods.DISPLAY_DEVICE>();
bool error = false;
for (int devId = 0; !error; devId++)
{
try
{
NativeMethods.DISPLAY_DEVICE device = new NativeMethods.DISPLAY_DEVICE();
device.cb = Marshal.SizeOf(typeof(NativeMethods.DISPLAY_DEVICE));
error = NativeMethods.EnumDisplayDevices(null, devId, ref device, 0) == 0;
if (String.IsNullOrWhiteSpace(device.DeviceID) == false)
{
devices.Add(device);
}
}
catch (Exception)
{
error = true;
}
}
return devices;
}
and to finish :
List<NativeMethods.DISPLAY_DEVICE> devices = GetAllDevice();
foreach (NativeMethods.DISPLAY_DEVICE device in devices)
{
NativeMethods.DISPLAY_DEVICE monitor = new NativeMethods.DISPLAY_DEVICE();
monitor.cb = Marshal.SizeOf(typeof(NativeMethods.DISPLAY_DEVICE));
NativeMethods.EnumDisplayDevices(device.DeviceName, 0, ref monitor, 0);
String monitorname = monitor.DeviceID.Split(new char[] { '\\' }, StringSplitOptions.RemoveEmptyEntries).Skip(1).FirstOrDefault();
GetMonitorDetail(monitorname);
}

i found this
public class NativeMethods
{
[DllImport("gdi32.dll", EntryPoint = "CreateDC", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CreateDC(string lpszDriver, string lpszDeviceName, string lpszOutput, IntPtr devMode);
[DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
static extern bool DeleteDC(IntPtr hdc);
[DllImport("gdi32.dll", SetLastError = true)]
private static extern Int32 GetDeviceCaps(IntPtr hdc, Int32 capindex);
private const int LOGPIXELSX = 88;
private static int _dpi = -1;
public static int DPI
{
get
{
if (_dpi != -1)
return _dpi;
_dpi = 96;
try
{
IntPtr hdc = CreateDC("DISPLAY", null, null, IntPtr.Zero);
if (hdc != IntPtr.Zero)
{
_dpi = GetDeviceCaps(hdc, LOGPIXELSX);
if (_dpi == 0)
_dpi = 96;
DeleteDC(hdc);
}
}
catch (Exception)
{
}
return _dpi;
}
}
}
that uses PInvoke to get the DPI in other question about the subject and i post it here because i only saw links.
i will mention this is not a common thing and i don't know why you will need that. this sounds like an A-B problem, so i'll say you need to be absolutly sure you need the DPI before using that
look at Lasse V. Karlsen comment please. this might not be accurate, so take that with care

Related

How to catch which user at network has the file open when the save operation fails?

I'm coding an console-application that write a query result in a .xlsx document. For this porpouse, I'm using the Microsoft.Office.Interop.Excel library with the Workbook.SaveAs() method to save the file in a shared folder on network.
How expected, when the file is already open, the code throws an exception to deal with this situation, but I need one more step: catch at least one user at network that has the file open, before the save operation fails.
Any idea?
To find out who works with a file if it has been opened, you should check through the file address to see if a process is running at that address. If yes, who is the owner of this process? Which is the user who locked the file. I put this under the full code.
In the static FileUtil class, a static method called WhoIsLocking(string path) returns the process that uses the file, and then in the GetProcessOwner(process.Id) method, it returns the name of the process owner.
Just a tip: Install the System.Management library via nuget
public string GetProcessOwner(int processId)
{
string query = "Select * From Win32_Process Where ProcessID = " + processId;
ManagementObjectSearcher searcher = new ManagementObjectSearcher(query);
ManagementObjectCollection processList = searcher.Get();
foreach (ManagementObject obj in processList)
{
string[] argList = new string[] { string.Empty, string.Empty };
int returnVal = Convert.ToInt32(obj.InvokeMethod("GetOwner", argList));
if (returnVal == 0)
{
// return DOMAIN\user
return argList[1] + "\\" + argList[0];
}
}
return "NO OWNER";
}
protected virtual bool IsFileLocked(FileInfo file)
{
try
{
using (FileStream stream = file.Open(FileMode.Open, FileAccess.Read, FileShare.None))
{
stream.Close();
}
}
catch (IOException)
{
return true;
}
//file is not locked
return false;
}
public void OpenFile(string path)
{
FileInfo fInfo = new FileInfo(path);
if (IsFileLocked(fInfo))
{
//get user name
var process = FileUtil.WhoIsLocking(path).FirstOrDefault();
string user = GetProcessOwner(process.Id);
}
else
{
//Open/read/write file
}
}
FileUtil class
static public class FileUtil {
[StructLayout(LayoutKind.Sequential)]
struct RM_UNIQUE_PROCESS
{
public int dwProcessId;
public System.Runtime.InteropServices.ComTypes.FILETIME ProcessStartTime;
}
const int RmRebootReasonNone = 0;
const int CCH_RM_MAX_APP_NAME = 255;
const int CCH_RM_MAX_SVC_NAME = 63;
enum RM_APP_TYPE {
RmUnknownApp = 0,
RmMainWindow = 1,
RmOtherWindow = 2,
RmService = 3,
RmExplorer = 4,
RmConsole = 5,
RmCritical = 1000
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
struct RM_PROCESS_INFO
{
public RM_UNIQUE_PROCESS Process;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_APP_NAME + 1)]
public string strAppName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_SVC_NAME + 1)]
public string strServiceShortName;
public RM_APP_TYPE ApplicationType;
public uint AppStatus;
public uint TSSessionId;
[MarshalAs(UnmanagedType.Bool)]
public bool bRestartable;
}
[DllImport("rstrtmgr.dll", CharSet = CharSet.Unicode)]
static extern int RmRegisterResources(uint pSessionHandle,
UInt32 nFiles,
string[] rgsFilenames,
UInt32 nApplications,
[In] RM_UNIQUE_PROCESS[] rgApplications,
UInt32 nServices,
string[] rgsServiceNames);
[DllImport("rstrtmgr.dll", CharSet = CharSet.Auto)]
static extern int RmStartSession(out uint pSessionHandle, int dwSessionFlags, string strSessionKey);
[DllImport("rstrtmgr.dll")]
static extern int RmEndSession(uint pSessionHandle);
[DllImport("rstrtmgr.dll")]
static extern int RmGetList(uint dwSessionHandle,
out uint pnProcInfoNeeded,
ref uint pnProcInfo,
[In, Out] RM_PROCESS_INFO[] rgAffectedApps,
ref uint lpdwRebootReasons);
/// <summary>
/// Find out what process(es) have a lock on the specified file.
/// </summary>
/// <param name="path">Path of the file.</param>
/// <returns>Processes locking the file</returns>
/// <remarks>See also:
/// http://msdn.microsoft.com/en-us/library/windows/desktop/aa373661(v=vs.85).aspx
/// http://wyupdate.googlecode.com/svn-history/r401/trunk/frmFilesInUse.cs (no copyright in code at time of viewing)
///
/// </remarks>
static public List < Process > WhoIsLocking(string path)
{
uint handle;
string key = Guid.NewGuid().ToString();
List < Process > processes = new List<Process>();
int res = RmStartSession(out handle, 0, key);
if (res != 0) throw new Exception("Could not begin restart session. Unable to determine file locker.");
try {
const int ERROR_MORE_DATA = 234;
uint pnProcInfoNeeded = 0,
pnProcInfo = 0,
lpdwRebootReasons = RmRebootReasonNone;
string[] resources = new string[] { path }; // Just checking on one resource.
res = RmRegisterResources(handle, (uint)resources.Length, resources, 0, null, 0, null);
if (res != 0) throw new Exception("Could not register resource.");
//Note: there's a race condition here -- the first call to RmGetList() returns
// the total number of process. However, when we call RmGetList() again to get
// the actual processes this number may have increased.
res = RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, null, ref lpdwRebootReasons);
if (res == ERROR_MORE_DATA) {
// Create an array to store the process results
RM_PROCESS_INFO[] processInfo = new RM_PROCESS_INFO[pnProcInfoNeeded];
pnProcInfo = pnProcInfoNeeded;
// Get the list
res = RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, processInfo, ref lpdwRebootReasons);
if (res == 0) {
processes = new List<Process>((int)pnProcInfo);
// Enumerate all of the results and add them to the
// list to be returned
for (int i = 0; i < pnProcInfo; i++)
{
try {
processes.Add(Process.GetProcessById(processInfo[i].Process.dwProcessId));
}
// catch the error -- in case the process is no longer running
catch (ArgumentException) { }
}
}
else throw new Exception("Could not list processes locking resource.");
}
else if (res != 0) throw new Exception("Could not list processes locking resource. Failed to get size of result.");
}
finally {
RmEndSession(handle);
}
return processes;
}
}
FileUtil class references : how-do-i-find-out-which-process-is-locking-a-file-using-net

RegEnumKeyEx - Access violation writing location

The situation:
Need to fetch a list of all subkeys of a particular registry key.
Need to access both 32bit and 64bit software keys, so I cannot use the Registry namespace.
Using CSharp in .Net 3.5, and registry functionality from advapi32.dll
I have most of the functionality working but I'm stuck on an error. When it reaches a key that contains values, it will either skip it or throw the following error:
"Unhandled exception at 0x00C819CD in xxxxx.exe: 0xC0000005: Access violation writing location 0x00720077."
If the error occurs, it does not land in either of my catch statements. It hard crashes the program. From what I've read on the forums, I believe it may be an issue with it writing to protected memory but all of the examples I see are for C++
My Declaration (from P/Invoke Interop Assistant):
[DllImportAttribute("advapi32.dll", EntryPoint = "RegEnumKeyExW")]
public static extern int RegEnumKeyExW(
[InAttribute()] IntPtr hKey,
uint dwIndex,
[OutAttribute()] [MarshalAsAttribute(UnmanagedType.LPWStr)] StringBuilder lpName,
ref uint lpcchName,
IntPtr lpReserved,
IntPtr lpClass,
IntPtr lpcchClass,
IntPtr lpftLastWriteTime);
My Function (obviously a work in progress so it's a bit messy):
static private List<string> GetSubKeys(UIntPtr inHive, String inKeyName, RegSAM in32or64key) {
int hkey = 0;
uint dwIndex = 0;
long enumStatus = 0;
List<string> keys = new List<string>();
try {
uint lResult = RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
inKeyName,
0,
(int)RegSAM.QueryValue | (int)RegSAM.EnumerateSubKeys | (int)in32or64key,
out hkey);
if (lResult == 0) {
while (enumStatus == ERROR_SUCCESS) {
StringBuilder lpName = new StringBuilder();
uint lpcchName = 256;
IntPtr lpReserved = IntPtr.Zero;
IntPtr lpClass = IntPtr.Zero;
IntPtr lpcchClass = IntPtr.Zero;
IntPtr lpftLastWriteTime = IntPtr.Zero;
enumStatus = RegEnumKeyExW(
(IntPtr)hkey,
dwIndex,
lpName,
ref lpcchName,
lpReserved,
lpClass,
lpcchClass,
lpftLastWriteTime);
switch (enumStatus) {
case ERROR_SUCCESS:
Console.WriteLine(string.Format("Key Found: {0}", lpName.ToString()));
break;
case ERROR_NO_MORE_ITEMS:
break;
default:
string error = new System.ComponentModel.Win32Exception((int)enumStatus).Message;
Console.WriteLine(string.Format("RegEnumKeyEx Error: {0}", error));
break;
}
dwIndex++;
}
} else {
Console.WriteLine(string.Format("RegOpenKey Error: {0}", lResult));
}
} catch (System.Runtime.InteropServices.COMException ex) {
Console.WriteLine(string.Format("COM Error: {0}", ex.Message));
} catch (Exception ex) {
Console.WriteLine(string.Format("Managed Error: {0}", ex.Message));
} finally {
if (0 != hkey) RegCloseKey(hkey);
}
return keys;
}
#endregion
StringBuilder lpName = new StringBuilder();
uint lpcchName = 256;
You are lying about the StringBuilder's capacity. It is 0, not 256. This will cause the pinvoke call to corrupt the GC heap. This eventually causes a hard crash, typically when a garbage collection takes place. Fix:
uint lpcchName = 256;
StringBuilder lpName = new StringBuilder(lpcchName);
Using the .NET RegistryKey.GetSubKeyNames() method instead would probably be wise.
Use the same way as. net4.0
static void Main(string[] args)
{
string displayName;
List<string> gInstalledSoftware = new List<string>();
using (var localMachine = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64))
{
var key = localMachine.OpenSubKey(#"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall", false);
foreach (String keyName in key.GetSubKeyNames())
{
RegistryKey subkey = key.OpenSubKey(keyName);
displayName = subkey.GetValue("DisplayName") as string;
if (string.IsNullOrEmpty(displayName))
continue;
gInstalledSoftware.Add(displayName);
}
}
}
You can try using. net source code to solve this problem. etc.
public class RegistryKey:
IDisposable
{
internal static readonly IntPtr HKEY_CLASSES_ROOT = new IntPtr(unchecked((int)0x80000000));
internal static readonly IntPtr HKEY_CURRENT_USER = new IntPtr(unchecked((int)0x80000001));
internal static readonly IntPtr HKEY_LOCAL_MACHINE = new IntPtr(unchecked((int)0x80000002));
internal static readonly IntPtr HKEY_USERS = new IntPtr(unchecked((int)0x80000003));
internal static readonly IntPtr HKEY_PERFORMANCE_DATA = new IntPtr(unchecked((int)0x80000004));
internal static readonly IntPtr HKEY_CURRENT_CONFIG = new IntPtr(unchecked((int)0x80000005));
private static readonly String[] hkeyNames = new String[] {
"HKEY_CLASSES_ROOT",
"HKEY_CURRENT_USER",
"HKEY_LOCAL_MACHINE",
"HKEY_USERS",
"HKEY_PERFORMANCE_DATA",
"HKEY_CURRENT_CONFIG",
};
public Object GetValue(String name)
{
return InternalGetValue(name, null, false, true);
}
internal Object InternalGetValue(String name, Object defaultValue, bool doNotExpand, bool checkSecurity)
{
Object data = defaultValue;
int type = 0;
int datasize = 0;
int ret = Win32Native.RegQueryValueEx(hkey, name, null, ref type, (byte[])null, ref datasize);
if (ret != 0)
{
if (IsPerfDataKey())
{
int size = 65000;
int sizeInput = size;
int r;
byte[] blob = new byte[size];
while (Win32Native.ERROR_MORE_DATA == (r = Win32Native.RegQueryValueEx(hkey, name, null, ref type, blob, ref sizeInput)))
{
if (size == Int32.MaxValue)
{
// ERROR_MORE_DATA was returned however we cannot increase the buffer size beyond Int32.MaxValue
//Win32Error(r, name);
Console.WriteLine(string.Format("[{0}] [{1}]", r,name));
}
else if (size > (Int32.MaxValue / 2))
{
// at this point in the loop "size * 2" would cause an overflow
size = Int32.MaxValue;
}
else
{
size *= 2;
}
sizeInput = size;
blob = new byte[size];
}
if (r != 0)
Console.WriteLine(string.Format("[{0}] [{1}]", r, name));
return blob;
}
else
{
// For stuff like ERROR_FILE_NOT_FOUND, we want to return null (data).
// Some OS's returned ERROR_MORE_DATA even in success cases, so we
// want to continue on through the function.
if (ret != Win32Native.ERROR_MORE_DATA)
return data;
}
}
if (datasize < 0)
{
// unexpected code path
//BCLDebug.Assert(false, "[InternalGetValue] RegQueryValue returned ERROR_SUCCESS but gave a negative datasize");
datasize = 0;
}
switch (type)
{
case Win32Native.REG_NONE:
case Win32Native.REG_DWORD_BIG_ENDIAN:
case Win32Native.REG_BINARY:
{
byte[] blob = new byte[datasize];
ret = Win32Native.RegQueryValueEx(hkey, name, null, ref type, blob, ref datasize);
data = blob;
}
break;
case Win32Native.REG_QWORD:
{ // also REG_QWORD_LITTLE_ENDIAN
if (datasize > 8)
{
// prevent an AV in the edge case that datasize is larger than sizeof(long)
goto case Win32Native.REG_BINARY;
}
long blob = 0;
//BCLDebug.Assert(datasize==8, "datasize==8");
// Here, datasize must be 8 when calling this
ret = Win32Native.RegQueryValueEx(hkey, name, null, ref type, ref blob, ref datasize);
data = blob;
}
break;
case Win32Native.REG_DWORD:
{ // also REG_DWORD_LITTLE_ENDIAN
if (datasize > 4)
{
// prevent an AV in the edge case that datasize is larger than sizeof(int)
goto case Win32Native.REG_QWORD;
}
int blob = 0;
// Here, datasize must be four when calling this
ret = Win32Native.RegQueryValueEx(hkey, name, null, ref type, ref blob, ref datasize);
data = blob;
}
break;
case Win32Native.REG_SZ:
{
if (datasize % 2 == 1)
{
// handle the case where the registry contains an odd-byte length (corrupt data?)
try
{
datasize = checked(datasize + 1);
}
catch (OverflowException e)
{
throw new IOException(("Arg_RegGetOverflowBug"), e);
}
}
char[] blob = new char[datasize / 2];
ret = Win32Native.RegQueryValueEx(hkey, name, null, ref type, blob, ref datasize);
if (blob.Length > 0 && blob[blob.Length - 1] == (char)0)
{
data = new String(blob, 0, blob.Length - 1);
}
else
{
// in the very unlikely case the data is missing null termination,
// pass in the whole char[] to prevent truncating a character
data = new String(blob);
}
}
break;
case Win32Native.REG_EXPAND_SZ:
{
if (datasize % 2 == 1)
{
// handle the case where the registry contains an odd-byte length (corrupt data?)
try
{
datasize = checked(datasize + 1);
}
catch (OverflowException e)
{
throw new IOException(("Arg_RegGetOverflowBug"), e);
}
}
char[] blob = new char[datasize / 2];
ret = Win32Native.RegQueryValueEx(hkey, name, null, ref type, blob, ref datasize);
if (blob.Length > 0 && blob[blob.Length - 1] == (char)0)
{
data = new String(blob, 0, blob.Length - 1);
}
else
{
// in the very unlikely case the data is missing null termination,
// pass in the whole char[] to prevent truncating a character
data = new String(blob);
}
if (!doNotExpand)
data = Environment.ExpandEnvironmentVariables((String)data);
}
break;
case Win32Native.REG_MULTI_SZ:
{
if (datasize % 2 == 1)
{
// handle the case where the registry contains an odd-byte length (corrupt data?)
try
{
datasize = checked(datasize + 1);
}
catch (OverflowException e)
{
throw new IOException(("Arg_RegGetOverflowBug"), e);
}
}
char[] blob = new char[datasize / 2];
ret = Win32Native.RegQueryValueEx(hkey, name, null, ref type, blob, ref datasize);
// make sure the string is null terminated before processing the data
if (blob.Length > 0 && blob[blob.Length - 1] != (char)0)
{
try
{
char[] newBlob = new char[checked(blob.Length + 1)];
for (int i = 0; i < blob.Length; i++)
{
newBlob[i] = blob[i];
}
newBlob[newBlob.Length - 1] = (char)0;
blob = newBlob;
}
catch (OverflowException e)
{
throw new IOException(("Arg_RegGetOverflowBug"), e);
}
blob[blob.Length - 1] = (char)0;
}
IList<String> strings = new List<String>();
int cur = 0;
int len = blob.Length;
while (ret == 0 && cur < len)
{
int nextNull = cur;
while (nextNull < len && blob[nextNull] != (char)0)
{
nextNull++;
}
if (nextNull < len)
{
//BCLDebug.Assert(blob[nextNull] == (char)0, "blob[nextNull] should be 0");
if (nextNull - cur > 0)
{
strings.Add(new String(blob, cur, nextNull - cur));
}
else
{
// we found an empty string. But if we're at the end of the data,
// it's just the extra null terminator.
if (nextNull != len - 1)
strings.Add(String.Empty);
}
}
else
{
strings.Add(new String(blob, cur, len - cur));
}
cur = nextNull + 1;
}
data = new String[strings.Count];
strings.CopyTo((String[])data, 0);
}
break;
case Win32Native.REG_LINK:
default:
break;
}
return data;
}
public String[] GetSubKeyNames()
{
return InternalGetSubKeyNames();
}
public RegistryKey OpenSubKey(string name, bool writable=false)
{
name = FixupName(name); // Fixup multiple slashes to a single slash
SafeRegistryHandle result = null;
int ret = Win32Native.RegOpenKeyEx(hkey,
name,
0,
GetRegistryKeyAccess(writable) | (int)regView,
out result);
if (ret == 0 && !result.IsInvalid)
{
RegistryKey key = new RegistryKey(result, writable, false, remoteKey, false, regView);
key.checkMode = GetSubKeyPermissonCheck(writable);
key.keyName = keyName + "\\" + name;
return key;
}
// Return null if we didn't find the key.
if (ret == Win32Native.ERROR_ACCESS_DENIED || ret == Win32Native.ERROR_BAD_IMPERSONATION_LEVEL)
{
// We need to throw SecurityException here for compatibility reasons,
// although UnauthorizedAccessException will make more sense.
//ThrowHelper.ThrowSecurityException(ExceptionResource.Security_RegistryPermission);
}
return null;
}
private const int MaxKeyLength = 255;
internal unsafe String[] InternalGetSubKeyNames()
{
int subkeys = InternalSubKeyCount();
String[] names = new String[subkeys]; // Returns 0-length array if empty.
if (subkeys > 0)
{
char[] name = new char[MaxKeyLength + 1];
int namelen;
fixed (char* namePtr = &name[0])
{
for (int i = 0; i < subkeys; i++)
{
namelen = name.Length; // Don't remove this. The API's doesn't work if this is not properly initialised.
int ret = Win32Native.RegEnumKeyEx(hkey,
i,
namePtr,
ref namelen,
null,
null,
null,
null);
if (ret != 0)
//Win32Error(ret, null);
Console.WriteLine(ret);
names[i] = new String(namePtr);
}
}
}
return names;
}
internal int InternalSubKeyCount()
{
int subkeys = 0;
int junk = 0;
int ret = Win32Native.RegQueryInfoKey(hkey,
null,
null,
IntPtr.Zero,
ref subkeys, // subkeys
null,
null,
ref junk, // values
null,
null,
null,
null);
if (ret != 0)
//Win32Error(ret, null);
Console.WriteLine(ret);
return subkeys;
}
public static RegistryKey OpenBaseKey(RegistryHive hKey, RegistryView view)
{
return GetBaseKey((IntPtr)((int)hKey), view);
}
internal static RegistryKey GetBaseKey(IntPtr hKey, RegistryView view)
{
int index = ((int)hKey) & 0x0FFFFFFF;
//BCLDebug.Assert(index >= 0 && index < hkeyNames.Length, "index is out of range!");
//BCLDebug.Assert((((int)hKey) & 0xFFFFFFF0) == 0x80000000, "Invalid hkey value!");
bool isPerf = hKey == HKEY_PERFORMANCE_DATA;
// only mark the SafeHandle as ownsHandle if the key is HKEY_PERFORMANCE_DATA.
SafeRegistryHandle srh = new SafeRegistryHandle(hKey, isPerf);
RegistryKey key = new RegistryKey(srh, true, true, false, isPerf, view);
key.checkMode = RegistryKeyPermissionCheck.Default;
key.keyName = hkeyNames[index];
return key;
}
private volatile SafeRegistryHandle hkey = null;
private volatile int state = 0;
private volatile String keyName;
private volatile bool remoteKey = false;
private volatile RegistryKeyPermissionCheck checkMode;
private volatile RegistryView regView = RegistryView.Default;
private const int STATE_DIRTY = 0x0001;
// SystemKey indicates that this is a "SYSTEMKEY" and shouldn't be "opened"
// or "closed".
//
private const int STATE_SYSTEMKEY = 0x0002;
// Access
//
private const int STATE_WRITEACCESS = 0x0004;
// Indicates if this key is for HKEY_PERFORMANCE_DATA
private const int STATE_PERF_DATA = 0x0008;
private RegistryKey(SafeRegistryHandle hkey, bool writable, bool systemkey, bool remoteKey, bool isPerfData, RegistryView view)
{
this.hkey = hkey;
this.keyName = "";
this.remoteKey = remoteKey;
this.regView = view;
if (systemkey)
{
this.state |= STATE_SYSTEMKEY;
}
if (writable)
{
this.state |= STATE_WRITEACCESS;
}
if (isPerfData)
this.state |= STATE_PERF_DATA;
}
private RegistryKeyPermissionCheck GetSubKeyPermissonCheck(bool subkeyWritable)
{
if (checkMode == RegistryKeyPermissionCheck.Default)
{
return checkMode;
}
if (subkeyWritable)
{
return RegistryKeyPermissionCheck.ReadWriteSubTree;
}
else
{
return RegistryKeyPermissionCheck.ReadSubTree;
}
}
static int GetRegistryKeyAccess(bool isWritable)
{
int winAccess;
if (!isWritable)
{
winAccess = Win32Native.KEY_READ;
}
else
{
winAccess = Win32Native.KEY_READ | Win32Native.KEY_WRITE;
}
return winAccess;
}
internal static String FixupName(String name)
{
//BCLDebug.Assert(name!=null,"[FixupName]name!=null");
if (name.IndexOf('\\') == -1)
return name;
StringBuilder sb = new StringBuilder(name);
FixupPath(sb);
int temp = sb.Length - 1;
if (temp >= 0 && sb[temp] == '\\') // Remove trailing slash
sb.Length = temp;
return sb.ToString();
}
private static void FixupPath(StringBuilder path)
{
//Contract.Requires(path != null);
int length = path.Length;
bool fixup = false;
char markerChar = (char)0xFFFF;
int i = 1;
while (i < length - 1)
{
if (path[i] == '\\')
{
i++;
while (i < length)
{
if (path[i] == '\\')
{
path[i] = markerChar;
i++;
fixup = true;
}
else
break;
}
}
i++;
}
if (fixup)
{
i = 0;
int j = 0;
while (i < length)
{
if (path[i] == markerChar)
{
i++;
continue;
}
path[j] = path[i];
i++;
j++;
}
path.Length += j - i;
}
}
#region IDisposable Support
private bool disposedValue = false; // 要检测冗余调用
public void Close()
{
Dispose(true);
}
protected virtual void Dispose(bool disposing)
{
if (hkey != null)
{
if (!IsSystemKey())
{
try
{
hkey.Dispose();
}
catch (IOException)
{
// we don't really care if the handle is invalid at this point
}
finally
{
hkey = null;
}
}
else if (disposing && IsPerfDataKey())
{
// System keys should never be closed. However, we want to call RegCloseKey
// on HKEY_PERFORMANCE_DATA when called from PerformanceCounter.CloseSharedResources
// (i.e. when disposing is true) so that we release the PERFLIB cache and cause it
// to be refreshed (by re-reading the registry) when accessed subsequently.
// This is the only way we can see the just installed perf counter.
// NOTE: since HKEY_PERFORMANCE_DATA is process wide, there is inherent race condition in closing
// the key asynchronously. While Vista is smart enough to rebuild the PERFLIB resources
// in this situation the down level OSes are not. We have a small window between
// the dispose below and usage elsewhere (other threads). This is By Design.
// This is less of an issue when OS > NT5 (i.e Vista & higher), we can close the perfkey
// (to release & refresh PERFLIB resources) and the OS will rebuild PERFLIB as necessary.
SafeRegistryHandle.RegCloseKey(RegistryKey.HKEY_PERFORMANCE_DATA);
}
}
}
private bool IsPerfDataKey()
{
return (this.state & STATE_PERF_DATA) != 0;
}
private bool IsSystemKey()
{
return (this.state & STATE_SYSTEMKEY) != 0;
}
public void Dispose()
{
Dispose(true);
}
#endregion
}
[System.Security.SecurityCritical]
public sealed class SafeRegistryHandle : SafeHandleZeroOrMinusOneIsInvalid
{
[System.Security.SecurityCritical]
internal SafeRegistryHandle() : base(true) { }
[System.Security.SecurityCritical]
public SafeRegistryHandle(IntPtr preexistingHandle, bool ownsHandle) : base(ownsHandle)
{
SetHandle(preexistingHandle);
}
[System.Security.SecurityCritical]
override protected bool ReleaseHandle()
{
return (RegCloseKey(handle) == Win32Native.ERROR_SUCCESS);
}
[DllImport(Win32Native.ADVAPI32)]
internal static extern int RegCloseKey(IntPtr hKey);
}
[Serializable]
[System.Runtime.InteropServices.ComVisible(true)]
public enum RegistryHive
{
ClassesRoot = unchecked((int)0x80000000),
CurrentUser = unchecked((int)0x80000001),
LocalMachine = unchecked((int)0x80000002),
Users = unchecked((int)0x80000003),
PerformanceData = unchecked((int)0x80000004),
CurrentConfig = unchecked((int)0x80000005),
}
public enum RegistryView
{
Default = 0, // 0x0000 operate on the default registry view
Registry64 = Win32Native.KEY_WOW64_64KEY, // 0x0100 operate on the 64-bit registry view
Registry32 = Win32Native.KEY_WOW64_32KEY, // 0x0200 operate on the 32-bit registry view
};
public enum RegistryKeyPermissionCheck
{
Default = 0,
ReadSubTree = 1,
ReadWriteSubTree = 2
}
public static class Win32Native
{
internal const String ADVAPI32 = "advapi32.dll";
internal const int KEY_WOW64_64KEY = 0x0100; //
internal const int KEY_WOW64_32KEY = 0x0200; //
internal const int ERROR_SUCCESS = 0x0;
internal const int READ_CONTROL = 0x00020000;
internal const int SYNCHRONIZE = 0x00100000;
internal const int STANDARD_RIGHTS_READ = READ_CONTROL;
internal const int STANDARD_RIGHTS_WRITE = READ_CONTROL;
internal const int KEY_QUERY_VALUE = 0x0001;
internal const int KEY_SET_VALUE = 0x0002;
internal const int KEY_CREATE_SUB_KEY = 0x0004;
internal const int KEY_ENUMERATE_SUB_KEYS = 0x0008;
internal const int KEY_NOTIFY = 0x0010;
internal const int KEY_CREATE_LINK = 0x0020;
internal const int KEY_READ = ((STANDARD_RIGHTS_READ |
KEY_QUERY_VALUE |
KEY_ENUMERATE_SUB_KEYS |
KEY_NOTIFY)
&
(~SYNCHRONIZE));
internal const int KEY_WRITE = ((STANDARD_RIGHTS_WRITE |
KEY_SET_VALUE |
KEY_CREATE_SUB_KEY)
&
(~SYNCHRONIZE));
internal const int ERROR_ACCESS_DENIED = 0x5;
internal const int ERROR_BAD_IMPERSONATION_LEVEL = 0x542;
[DllImport(ADVAPI32, CharSet = CharSet.Auto, BestFitMapping = false)]
internal static extern int RegOpenKeyEx(SafeRegistryHandle hKey, String lpSubKey,
int ulOptions, int samDesired, out SafeRegistryHandle hkResult);
[DllImport(ADVAPI32, CharSet = CharSet.Auto, BestFitMapping = false)]
internal static extern int RegQueryInfoKey(SafeRegistryHandle hKey, [Out]StringBuilder lpClass,
int[] lpcbClass, IntPtr lpReserved_MustBeZero, ref int lpcSubKeys,
int[] lpcbMaxSubKeyLen, int[] lpcbMaxClassLen,
ref int lpcValues, int[] lpcbMaxValueNameLen,
int[] lpcbMaxValueLen, int[] lpcbSecurityDescriptor,
int[] lpftLastWriteTime);
[DllImport(ADVAPI32, CharSet = CharSet.Auto, BestFitMapping = false)]
internal unsafe static extern int RegEnumKeyEx(SafeRegistryHandle hKey, int dwIndex,
char* lpName, ref int lpcbName, int[] lpReserved,
[Out]StringBuilder lpClass, int[] lpcbClass,
long[] lpftLastWriteTime);
internal const int ERROR_MORE_DATA = 0xEA;
internal const int REG_NONE = 0; // No value type
internal const int REG_DWORD_BIG_ENDIAN = 5; // 32-bit number
internal const int REG_BINARY = 3; // Free form binary
internal const int REG_QWORD = 11; // 64-bit number
internal const int REG_DWORD = 4; // 32-bit number
internal const int REG_SZ = 1; // Unicode nul terminated string
internal const int REG_EXPAND_SZ = 2; // Unicode nul terminated string
internal const int REG_MULTI_SZ = 7; // Multiple Unicode strings
internal const int REG_LINK = 6; // Symbolic Link (unicode)
[DllImport(ADVAPI32, CharSet = CharSet.Auto, BestFitMapping = false)]
internal static extern int RegQueryValueEx(SafeRegistryHandle hKey, String lpValueName,
int[] lpReserved, ref int lpType, [Out] byte[] lpData,
ref int lpcbData);
[DllImport(ADVAPI32, CharSet = CharSet.Auto, BestFitMapping = false)]
internal static extern int RegQueryValueEx(SafeRegistryHandle hKey, String lpValueName,
int[] lpReserved, ref int lpType, ref int lpData,
ref int lpcbData);
[DllImport(ADVAPI32, CharSet = CharSet.Auto, BestFitMapping = false)]
internal static extern int RegQueryValueEx(SafeRegistryHandle hKey, String lpValueName,
int[] lpReserved, ref int lpType, ref long lpData,
ref int lpcbData);
[DllImport(ADVAPI32, CharSet = CharSet.Auto, BestFitMapping = false)]
internal static extern int RegQueryValueEx(SafeRegistryHandle hKey, String lpValueName,
int[] lpReserved, ref int lpType, [Out] char[] lpData,
ref int lpcbData);
[DllImport(ADVAPI32, CharSet = CharSet.Auto, BestFitMapping = false)]
internal static extern int RegQueryValueEx(SafeRegistryHandle hKey, String lpValueName,
int[] lpReserved, ref int lpType, [Out]StringBuilder lpData,
ref int lpcbData);
}

WIN32API returns only current machine name

I want to collect all list of machines in local network, for that I am trying below code. But it always return me current machine name only. How Can I get all machines ip/name in local network?.
I have tried all SV_101_TYPES, among these some returns empty list and remaining returns only current machine name.
Could anyone guide me, what is wrong?
public class Program
{
static void Main(string[] args)
{
ArrayList machines = NetApi32.GetServerList(NetApi32.SV_101_TYPES.SV_TYPE_ALL);
}
}
/// <summary>
/// Summary description for Class1.
/// </summary>
///
public class NetApi32
{
// constants
public const uint ERROR_SUCCESS = 0;
public const uint ERROR_MORE_DATA = 234;
public enum SV_101_TYPES : uint
{
SV_TYPE_WORKSTATION = 0x00000001,
SV_TYPE_SERVER = 0x00000002,
SV_TYPE_SQLSERVER = 0x00000004,
SV_TYPE_DOMAIN_CTRL = 0x00000008,
SV_TYPE_DOMAIN_BAKCTRL = 0x00000010,
SV_TYPE_TIME_SOURCE = 0x00000020,
SV_TYPE_AFP = 0x00000040,
SV_TYPE_NOVELL = 0x00000080,
SV_TYPE_DOMAIN_MEMBER = 0x00000100,
SV_TYPE_PRINTQ_SERVER = 0x00000200,
SV_TYPE_DIALIN_SERVER = 0x00000400,
SV_TYPE_XENIX_SERVER = 0x00000800,
SV_TYPE_SERVER_UNIX = 0x00000800,
SV_TYPE_NT = 0x00001000,
SV_TYPE_WFW = 0x00002000,
SV_TYPE_SERVER_MFPN = 0x00004000,
SV_TYPE_SERVER_NT = 0x00008000,
SV_TYPE_POTENTIAL_BROWSER = 0x00010000,
SV_TYPE_BACKUP_BROWSER = 0x00020000,
SV_TYPE_MASTER_BROWSER = 0x00040000,
SV_TYPE_DOMAIN_MASTER = 0x00080000,
SV_TYPE_SERVER_OSF = 0x00100000,
SV_TYPE_SERVER_VMS = 0x00200000,
SV_TYPE_WINDOWS = 0x00400000,
SV_TYPE_DFS = 0x00800000,
SV_TYPE_CLUSTER_NT = 0x01000000,
SV_TYPE_TERMINALSERVER = 0x02000000,
SV_TYPE_CLUSTER_VS_NT = 0x04000000,
SV_TYPE_DCE = 0x10000000,
SV_TYPE_ALTERNATE_XPORT = 0x20000000,
SV_TYPE_LOCAL_LIST_ONLY = 0x40000000,
SV_TYPE_DOMAIN_ENUM = 0x80000000,
SV_TYPE_ALL = 0xFFFFFFFF
};
[StructLayout(LayoutKind.Sequential)]
public struct SERVER_INFO_101
{
[MarshalAs(System.Runtime.InteropServices.UnmanagedType.U4)]
public UInt32 sv101_platform_id;
[MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPWStr)]
public string sv101_name;
[MarshalAs(System.Runtime.InteropServices.UnmanagedType.U4)]
public UInt32 sv101_version_major;
[MarshalAs(System.Runtime.InteropServices.UnmanagedType.U4)]
public UInt32 sv101_version_minor;
[MarshalAs(System.Runtime.InteropServices.UnmanagedType.U4)]
public UInt32 sv101_type;
[MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPWStr)]
public string sv101_comment;
};
public enum PLATFORM_ID
{
PLATFORM_ID_DOS = 300,
PLATFORM_ID_OS2 = 400,
PLATFORM_ID_NT = 500,
PLATFORM_ID_OSF = 600,
PLATFORM_ID_VMS = 700
}
[DllImport("netapi32.dll", EntryPoint = "NetServerEnum")]
public static extern int NetServerEnum([MarshalAs(UnmanagedType.LPWStr)]string servername,
int level,
out IntPtr bufptr,
int prefmaxlen,
ref int entriesread,
ref int totalentries,
SV_101_TYPES servertype,
[MarshalAs(UnmanagedType.LPWStr)]string domain,
IntPtr resume_handle);
[DllImport("netapi32.dll", EntryPoint = "NetApiBufferFree")]
public static extern int
NetApiBufferFree(IntPtr buffer);
[DllImport("Netapi32", CharSet = CharSet.Unicode)]
private static extern int NetMessageBufferSend(
string servername,
string msgname,
string fromname,
string buf,
int buflen);
public static int NetMessageSend(string serverName, string messageName, string fromName, string strMsgBuffer, int iMsgBufferLen)
{
return NetMessageBufferSend(serverName, messageName, fromName, strMsgBuffer, iMsgBufferLen * 2);
}
public static ArrayList GetServerList(NetApi32.SV_101_TYPES ServerType)
{
int entriesread = 0, totalentries = 0;
ArrayList alServers = new ArrayList();
do
{
// Buffer to store the available servers
// Filled by the NetServerEnum function
IntPtr buf = new IntPtr();
SERVER_INFO_101 server;
int ret = NetServerEnum(null, 101, out buf, -1, ref entriesread, ref totalentries, ServerType, null, IntPtr.Zero);
// if the function returned any data, fill the tree view
if (ret == ERROR_SUCCESS ||
ret == ERROR_MORE_DATA ||
entriesread > 0)
{
IntPtr ptr = buf;
for (int i = 0; i < entriesread; i++)
{
// cast pointer to a SERVER_INFO_101 structure
server = (SERVER_INFO_101)Marshal.PtrToStructure(ptr, typeof(SERVER_INFO_101));
//Cast the pointer to a ulong so this addition will work on 32-bit or 64-bit systems.
ptr = (IntPtr)((ulong)ptr + (ulong)Marshal.SizeOf(server));
// add the machine name and comment to the arrayList.
//You could return the entire structure here if desired
alServers.Add(server);
}
}
// free the buffer
NetApiBufferFree(buf);
}
while
(
entriesread < totalentries &&
entriesread != 0
);
return alServers;
}
}

Eject USB device via C#

I was looking for a short way to eject USB-devices via C#-code, so I coded a little class myself, yet it simply doesn't work. Since there's no popup that says "Lock success!" I assume that the problem relies within the "LockVolume"-function, but I don't know where.
Does anybody see the mistake I made?
class USBEject
{
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern IntPtr CreateFile(
string lpFileName,
uint dwDesiredAccess,
uint dwShareMode,
IntPtr SecurityAttributes,
uint dwCreationDisposition,
uint dwFlagsAndAttributes,
IntPtr hTemplateFile
);
[DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
private static extern bool DeviceIoControl(
IntPtr hDevice,
uint dwIoControlCode,
IntPtr lpInBuffer,
uint nInBufferSize,
IntPtr lpOutBuffer,
uint nOutBufferSize,
out uint lpBytesReturned,
IntPtr lpOverlapped
);
[DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
private static extern bool DeviceIoControl(
IntPtr hDevice,
uint dwIoControlCode,
byte[] lpInBuffer,
uint nInBufferSize,
IntPtr lpOutBuffer,
uint nOutBufferSize,
out uint lpBytesReturned,
IntPtr lpOverlapped
);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CloseHandle(IntPtr hObject);
private IntPtr handle = IntPtr.Zero;
const int GENERIC_READ = 0x80000000;
const int GENERIC_WRITE = 0x40000000;
const int FILE_SHARE_READ = 0x1;
const int FILE_SHARE_WRITE = 0x2;
const int FSCTL_LOCK_VOLUME = 0x00090018;
const int FSCTL_DISMOUNT_VOLUME = 0x00090020;
const int IOCTL_STORAGE_EJECT_MEDIA = 0x2D4808;
const int IOCTL_STORAGE_MEDIA_REMOVAL = 0x002D4804;
/// <summary>
/// Constructor for the USBEject class
/// </summary>
/// <param name="driveLetter">This should be the drive letter. Format: F:/, C:/..</param>
public USBEject(string driveLetter)
{
string filename = #"\\.\" + driveLetter[0] + ":";
handle = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, 0x3, 0, IntPtr.Zero);
}
public bool Eject()
{
if (LockVolume(handle) && DismountVolume(handle))
{
PreventRemovalOfVolume(handle, false);
return AutoEjectVolume(handle);
}
return false;
}
private bool LockVolume(IntPtr handle)
{
uint byteReturned;
for (int i = 0; i < 10; i++)
{
if (DeviceIoControl(handle, FSCTL_LOCK_VOLUME, IntPtr.Zero, 0, IntPtr.Zero, 0, out byteReturned, IntPtr.Zero))
{
System.Windows.Forms.MessageBox.Show("Lock success!");
return true;
}
Thread.Sleep(500);
}
return false;
}
private bool PreventRemovalOfVolume(IntPtr handle, bool prevent)
{
byte[] buf = new byte[1];
uint retVal;
buf[0] = (prevent) ? (byte)1 : (byte)0;
return DeviceIoControl(handle, IOCTL_STORAGE_MEDIA_REMOVAL, buf, 1, IntPtr.Zero, 0, out retVal, IntPtr.Zero);
}
private bool DismountVolume(IntPtr handle)
{
uint byteReturned;
return DeviceIoControl(handle, FSCTL_DISMOUNT_VOLUME, IntPtr.Zero, 0, IntPtr.Zero, 0, out byteReturned, IntPtr.Zero);
}
private bool AutoEjectVolume(IntPtr handle)
{
uint byteReturned;
return DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA, IntPtr.Zero, 0, IntPtr.Zero, 0, out byteReturned, IntPtr.Zero);
}
private bool CloseVolume(IntPtr handle)
{
return CloseHandle(handle);
}
}
Changed just a little bit your code and it goes as follows:
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern IntPtr CreateFile(
string lpFileName,
uint dwDesiredAccess,
uint dwShareMode,
IntPtr SecurityAttributes,
uint dwCreationDisposition,
uint dwFlagsAndAttributes,
IntPtr hTemplateFile
);
[DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
private static extern bool DeviceIoControl(
IntPtr hDevice,
uint dwIoControlCode,
IntPtr lpInBuffer,
uint nInBufferSize,
IntPtr lpOutBuffer,
uint nOutBufferSize,
out uint lpBytesReturned,
IntPtr lpOverlapped
);
[DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
private static extern bool DeviceIoControl(
IntPtr hDevice,
uint dwIoControlCode,
byte[] lpInBuffer,
uint nInBufferSize,
IntPtr lpOutBuffer,
uint nOutBufferSize,
out uint lpBytesReturned,
IntPtr lpOverlapped
);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CloseHandle(IntPtr hObject);
private IntPtr handle = IntPtr.Zero;
const uint GENERIC_READ = 0x80000000;
const uint GENERIC_WRITE = 0x40000000;
const int FILE_SHARE_READ = 0x1;
const int FILE_SHARE_WRITE = 0x2;
const int FSCTL_LOCK_VOLUME = 0x00090018;
const int FSCTL_DISMOUNT_VOLUME = 0x00090020;
const int IOCTL_STORAGE_EJECT_MEDIA = 0x2D4808;
const int IOCTL_STORAGE_MEDIA_REMOVAL = 0x002D4804;
/// <summary>
/// Constructor for the USBEject class
/// </summary>
/// <param name="driveLetter">This should be the drive letter. Format: F:/, C:/..</param>
public IntPtr USBEject(string driveLetter)
{
string filename = #"\\.\" + driveLetter[0] + ":";
return CreateFile(filename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, 0x3, 0, IntPtr.Zero);
}
public bool Eject(IntPtr handle)
{
bool result = false;
if (LockVolume(handle) && DismountVolume(handle))
{
PreventRemovalOfVolume(handle, false);
result = AutoEjectVolume(handle);
}
CloseHandle(handle);
return result;
}
private bool LockVolume(IntPtr handle)
{
uint byteReturned;
for (int i = 0; i < 10; i++)
{
if (DeviceIoControl(handle, FSCTL_LOCK_VOLUME, IntPtr.Zero, 0, IntPtr.Zero, 0, out byteReturned, IntPtr.Zero))
{
System.Windows.Forms.MessageBox.Show("Lock success!");
return true;
}
Thread.Sleep(500);
}
return false;
}
private bool PreventRemovalOfVolume(IntPtr handle, bool prevent)
{
byte[] buf = new byte[1];
uint retVal;
buf[0] = (prevent) ? (byte)1 : (byte)0;
return DeviceIoControl(handle, IOCTL_STORAGE_MEDIA_REMOVAL, buf, 1, IntPtr.Zero, 0, out retVal, IntPtr.Zero);
}
private bool DismountVolume(IntPtr handle)
{
uint byteReturned;
return DeviceIoControl(handle, FSCTL_DISMOUNT_VOLUME, IntPtr.Zero, 0, IntPtr.Zero, 0, out byteReturned, IntPtr.Zero);
}
private bool AutoEjectVolume(IntPtr handle)
{
uint byteReturned;
return DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA, IntPtr.Zero, 0, IntPtr.Zero, 0, out byteReturned, IntPtr.Zero);
}
private bool CloseVolume(IntPtr handle)
{
return CloseHandle(handle);
}
So you can use it in two ways:
handle = USBEject("D:");
Eject(handle);
or directly:
Eject(USBEject("D:"));
It works for me on my Windows 10 machine (preview 14291)
Found the answer for my issue by using some of Roger Deep's code for the CreateFile call.
My code to remove a USB drive inside WPF Window:
private void Button_Click_1(object sender, RoutedEventArgs e)
{
EjectDrive('K');
}
void EjectDrive(char driveLetter)
{
string path = #"\\.\" + driveLetter + #":";
IntPtr handle = CreateFile(path, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, 0x3, 0, IntPtr.Zero);
if ((long)handle == -1)
{
MessageBox.Show("Unable to open drive " + driveLetter);
return;
}
int dummy = 0;
DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA, IntPtr.Zero, 0,
IntPtr.Zero, 0, ref dummy, IntPtr.Zero);
CloseHandle(handle);
MessageBox.Show("OK to remove drive.");
}
[DllImport("kernel32", SetLastError = true)]
private static extern IntPtr CreateFile
(string filename, uint desiredAccess,
uint shareMode, IntPtr securityAttributes,
int creationDisposition, int flagsAndAttributes,
IntPtr templateFile);
[DllImport("kernel32")]
private static extern int DeviceIoControl
(IntPtr deviceHandle, uint ioControlCode,
IntPtr inBuffer, int inBufferSize,
IntPtr outBuffer, int outBufferSize,
ref int bytesReturned, IntPtr overlapped);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CloseHandle(IntPtr hObject);
Here's some code that I converted from a powershell script. You need to run with admin privileges and It works to "unmount" the USB drive. However, when you try to unplug the USB drive and plug it in again, it doesn't show up as a drive letter. (To get around that you need to type "WindowsKey-X" and select Disk-Manager to reassign the drive less to the USB device. (If anybody knows how to fix that problem please post to commits.) Here's the Code:
// Right click Project and Add Reference to System.Management.dll
using System.Management;
string mq = "SELECT * FROM Win32_Volume Where Name = 'E:\\'";
ManagementObjectSearcher ms = new ManagementObjectSearcher(mq);
foreach (ManagementObject mo in ms.Get())
{
mo["DriveLetter"] = null;
mo.Put();
ManagementBaseObject inParams = mo.GetMethodParameters("Dismount");
inParams["Force"] = false;
inParams["Permanent"] = false;
mo.InvokeMethod("Dismount", inParams, null);
}
Note that the powershell script also has the same problem of reattaching the USB device after ejecting. Here's the powershell script for your reference:
$vol = get-wmiobject -Class Win32_Volume |
where{$_.Name -eq 'E:\'}
$vol.DriveLetter = $null
$vol.Put()
$vol.Dismount($false, $false)
Here's a class that I just wrote to Manage Mounting and Unmounting of Removable USB Drives using WMI:
using System;
using System.IO;
using System.Text;
using System.Windows;
using System.Management; //<-- right-click on project and add reference
using System.Collections.Generic;
using System.Text.RegularExpressions;
// This Class implements Mount/Unmount for USB Removable Drives
// in a way similar to "Disk Manager" in the Control Panel.
//
// Currently, It doesn't implement "Eject" like when you right
// right-click on the USB icon on lower right of screen.
// The "Unmount" is similar to "Eject" except it dosn't
// cleanup the registry so that the USB drive can be automatically
// recognized again without manually mounting it from "Disk Manager"
// If somebody knows how to fix this class to gain this function...
// please post it to their thread. Thanks.
namespace WPM {
public struct UsbDriveItem_t {
public int Index;
public string DeviceId;
public char DriveLetter;
public string Label;
public override string ToString() {
if (Index < 0)
return "<none>";
else
return String.Format("{0}: {1}", DriveLetter, Label);
}
};
delegate void UsbEvent();
class UsbDriveRemovable {
public static int Unmount(char DriveLetter) {
bool success = ValidateAdmin("UsbDriveRemovable.Unmount()");
if (!success) return -1;
string Name = "'" + DriveLetter + ":\\\\'";
string mq = "SELECT * FROM Win32_Volume Where Name = " + Name;
ManagementObjectSearcher ms = new ManagementObjectSearcher(mq);
ManagementObjectCollection mc = ms.Get();
foreach (ManagementObject mo in mc) {
var DriveLetterI = mo["DriveLetter"].ToString();
mo["DriveLetter"] = null;
mo.Put();
ManagementBaseObject inParams = mo.GetMethodParameters("Dismount");
inParams["Force"] = false;
inParams["Permanent"] = false;
ManagementBaseObject outParams = mo.InvokeMethod("Dismount", inParams, null);
string rc = outParams["ReturnValue"].ToString();
mo.Dispose();
}
mc.Dispose();
ms.Dispose();
return 0;
}
public static int Mount(string DeviceId, char Letter = '?') {
bool success = ValidateAdmin("UsbDriveRemovable.Mount()");
if (!success) return -1;
if (Letter == '?' || Letter == '#') {
GetFirstUnsedLetter(out Letter);
}
string FixDeviceId = Regex.Replace(DeviceId, #"\\", #"\\");
string mq = "SELECT * FROM Win32_Volume WHERE DeviceId = '"
+ FixDeviceId
+ "'";
ManagementObjectSearcher ms = new ManagementObjectSearcher(mq);
ManagementObjectCollection mc = ms.Get();
foreach (ManagementObject mo in mc) {
ManagementBaseObject inParams = mo.GetMethodParameters("AddMountPoint");
inParams["Directory"] = Letter + ":\\";
ManagementBaseObject outParams = mo.InvokeMethod("AddMountPoint", inParams, null);
string rc = outParams["ReturnValue"].ToString();
mo.Dispose();
}
mc.Dispose();
ms.Dispose();
return 0;
}
/*List<UsbDriveItem_t>*/
public static int ListDrives(ref List<UsbDriveItem_t> DriveList) {
DriveList.Clear();
string mq = "SELECT * FROM Win32_Volume Where DriveType = '2'";
ManagementObjectSearcher ms = new ManagementObjectSearcher(mq);
ManagementObjectCollection mc = ms.Get();
int count = 0;
foreach (ManagementObject mo in mc) {
UsbDriveItem_t item = new UsbDriveItem_t();
item.Index = count;
item.Label = (mo["Label"] == null) ? "<none>" : mo["Label"].ToString();
item.DriveLetter = (mo["DriveLetter"] == null) ? '#' : mo["DriveLetter"].ToString()[0];
item.DeviceId = (mo["DeviceId"] == null) ? "<none>" : mo["DeviceId"].ToString();
DriveList.Add(item);
mo.Dispose();
}
count++;
mc.Dispose();
ms.Dispose();
return 0;
}
public static void MountItem(UsbDriveItem_t DriveItem) {
char DriveLetter = DriveItem.DriveLetter;
string DriveLabel = DriveItem.Label;
string DeviceId = DriveItem.DeviceId;
// Mount Drive if its not already Mounted
if (DriveLetter == '#') {
UsbDriveRemovable.GetFirstUnsedLetter(out DriveLetter);
UsbDriveRemovable.Mount(DeviceId, DriveLetter);
}
return;
}
public static void UnmountItem(UsbDriveItem_t DriveItem) {
char DriveLetter = DriveItem.DriveLetter;
UsbDriveRemovable.Unmount(DriveLetter);
return;
}
public static int GetFirstUnsedLetter(out char Letter) {
bool[] alphabet = new bool[26];
for (int i=0; i < 26; i++) {
alphabet[i] = false;
}
string mq = "SELECT * FROM Win32_Volume";
ManagementObjectSearcher ms = new ManagementObjectSearcher(mq);
ManagementObjectCollection mc = ms.Get();
foreach (ManagementObject mo in mc) {
if (mo["DriveLetter"] != null) {
char cc = mo["DriveLetter"].ToString()[0];
int ci = char.ToUpper(cc) - 65;
alphabet[ci] = true;
}
mo.Dispose();
}
mc.Dispose();
ms.Dispose();
int found = -1;
for (int i=3; i < 26; i++) {
if (alphabet[i] == false) {
found = i;
break;
}
}
if (found >= 0) {
Letter = (char)(found + 65);
return 0;
}
else {
Letter = '?';
return -1;
}
}
public static object
RegisterInsertEvent(UsbEvent InsertEvent) {
var insertQuery = new WqlEventQuery("SELECT * FROM Win32_DeviceChangeEvent WHERE EventType = 2");
var insertWatcher = new ManagementEventWatcher(insertQuery);
insertWatcher.EventArrived += delegate(object sender, EventArrivedEventArgs e) {
// string driveName = e.NewEvent.Properties["DriveName"].Value.ToString();
Action action = delegate {
InsertEvent();
};
Application.Current.Dispatcher.BeginInvoke(action);
};
insertWatcher.Start();
return (object)insertWatcher;
}
public static object RegisterRemoveEvent(UsbEvent RemoveEvent) {
var removeQuery = new WqlEventQuery("SELECT * FROM Win32_DeviceChangeEvent WHERE EventType = 3");
var removeWatcher = new ManagementEventWatcher(removeQuery);
removeWatcher.EventArrived += delegate(object sender, EventArrivedEventArgs e) {
// string driveName = e.NewEvent.Properties["DriveName"].Value.ToString();
Action action = delegate {
RemoveEvent();
};
Application.Current.Dispatcher.BeginInvoke(action);
};
removeWatcher.Start();
return (object)removeWatcher;
}
// Mount all UsbRemovable Drives that are not currently mounted
public static int MountAll() {
List<UsbDriveItem_t> DriveList = new List<UsbDriveItem_t>();
ListDrives(ref DriveList);
foreach (UsbDriveItem_t item in DriveList) {
if (item.DriveLetter == '?') {
Mount(item.DeviceId);
}
}
return 0;
}
// Unmount all UsbRemovable Drives
public static int UnmountAll() {
List<UsbDriveItem_t> DriveList = new List<UsbDriveItem_t>();
ListDrives(ref DriveList);
foreach (UsbDriveItem_t item in DriveList) {
if (item.DriveLetter != '?') {
Unmount(item.DriveLetter);
}
}
return 0;
}
public static bool IsAdministrator()
{
var id = System.Security.Principal.WindowsIdentity.GetCurrent();
var prin = new System.Security.Principal.WindowsPrincipal(id);
return prin.IsInRole(
System.Security.Principal.WindowsBuiltInRole.Administrator);
}
public static bool ValidateAdmin(string CalledFrom = null) {
if (CalledFrom == null) {
CalledFrom = "";
}
if (!IsAdministrator()) {
string msg = "Please rerun this application with admin privileges.\r\n\r\n"
+ "Access denied to call " + CalledFrom + "\r\n\r\n";
MessageBox.Show(msg, "ERROR");
return false;
}
return true;
}
public static void StartExplorer(char DriveLetter)
{
var proc1 = new System.Diagnostics.Process();
proc1.StartInfo.FileName = #"C:\\Windows\\System32\\explorer.exe";
proc1.StartInfo.Arguments = DriveLetter.ToString();
proc1.StartInfo.CreateNoWindow = true;
proc1.StartInfo.UseShellExecute = false;
proc1.StartInfo.RedirectStandardOutput = true;
proc1.StartInfo.RedirectStandardError = true;
proc1.Start();
proc1.WaitForExit();
string proc1out = proc1.StandardOutput.ReadToEnd();
string proc1err = proc1.StandardError.ReadToEnd();
//if (proc1.ExitCode != 0) {
// string msg = proc1out + "\r\n\r\n" + proc1err;
// MessageBox.Show(msg, "Error: Mountvol /R");
//}
proc1.Close();
}
} //class
} //namespace
/* DOESN'T WORK WELL...
// Kludge to get USB Drive to be recognized again
void UsbCleanup() {
var proc1 = new System.Diagnostics.Process();
proc1.StartInfo.FileName = #"C:\\Windows\\System32\\mountvol.exe";
proc1.StartInfo.Arguments = #"/R";
proc1.StartInfo.CreateNoWindow = true;
proc1.StartInfo.UseShellExecute = false;
proc1.StartInfo.RedirectStandardOutput = true;
proc1.StartInfo.RedirectStandardError = true;
proc1.Start();
proc1.WaitForExit();
string proc1out = proc1.StandardOutput.ReadToEnd();
string proc1err = proc1.StandardError.ReadToEnd();
if (proc1.ExitCode != 0) {
string msg = proc1out + "\r\n\r\n" + proc1err;
MessageBox.Show(msg, "Error: Mountvol /R");
}
proc1.Close();
var proc2 = new System.Diagnostics.Process();
proc2.StartInfo.FileName = #"C:\\Windows\\System32\\mountvol.exe";
proc2.StartInfo.Arguments = #"/E";
proc2.StartInfo.CreateNoWindow = true;
proc2.StartInfo.UseShellExecute = false;
proc2.StartInfo.RedirectStandardOutput = true;
proc2.StartInfo.RedirectStandardError = true;
proc2.Start();
proc2.WaitForExit();
string proc2out = proc2.StandardOutput.ReadToEnd();
string proc2err = proc2.StandardError.ReadToEnd();
if (proc2.ExitCode != 0) {
string msg = proc1out + "\r\n\r\n" + proc1err;
MessageBox.Show(msg, "Error: Mountvol /E");
}
proc2.Close();
return;
}
*/
You could convert the following PowerShell into C#:
$Eject = New-Object -comObject Shell.Application
$Eject.NameSpace(17).ParseName($usbDrvLetter+“:”).InvokeVerb(“Eject”)

How to find the Number of CPU Cores via .NET/C#?

Is there a way via .NET/C# to find out the number of CPU cores?
PS This is a straight code question, not a "Should I use multi-threading?" question! :-)
There are several different pieces of information relating to processors that you could get:
Number of physical processors
Number of cores
Number of logical processors.
These can all be different; in the case of a machine with 2 dual-core hyper-threading-enabled processors, there are 2 physical processors, 4 cores, and 8 logical processors.
The number of logical processors is available through the Environment class, but the other information is only available through WMI (and you may have to install some hotfixes or service packs to get it on some systems):
Make sure to add a reference in your project to System.Management.dll
In .NET Core, this is available (for Windows only) as a NuGet package.
Physical Processors:
foreach (var item in new System.Management.ManagementObjectSearcher("Select * from Win32_ComputerSystem").Get())
{
Console.WriteLine("Number Of Physical Processors: {0} ", item["NumberOfProcessors"]);
}
Cores:
int coreCount = 0;
foreach (var item in new System.Management.ManagementObjectSearcher("Select * from Win32_Processor").Get())
{
coreCount += int.Parse(item["NumberOfCores"].ToString());
}
Console.WriteLine("Number Of Cores: {0}", coreCount);
Logical Processors:
Console.WriteLine("Number Of Logical Processors: {0}", Environment.ProcessorCount);
OR
foreach (var item in new System.Management.ManagementObjectSearcher("Select * from Win32_ComputerSystem").Get())
{
Console.WriteLine("Number Of Logical Processors: {0}", item["NumberOfLogicalProcessors"]);
}
Processors excluded from Windows:
You can also use Windows API calls in setupapi.dll to discover processors that have been excluded from Windows (e.g. through boot settings) and aren't detectable using the above means. The code below gives the total number of logical processors (I haven't been able to figure out how to differentiate physical from logical processors) that exist, including those that have been excluded from Windows:
static void Main(string[] args)
{
int deviceCount = 0;
IntPtr deviceList = IntPtr.Zero;
// GUID for processor classid
Guid processorGuid = new Guid("{50127dc3-0f36-415e-a6cc-4cb3be910b65}");
try
{
// get a list of all processor devices
deviceList = SetupDiGetClassDevs(ref processorGuid, "ACPI", IntPtr.Zero, (int)DIGCF.PRESENT);
// attempt to process each item in the list
for (int deviceNumber = 0; ; deviceNumber++)
{
SP_DEVINFO_DATA deviceInfo = new SP_DEVINFO_DATA();
deviceInfo.cbSize = Marshal.SizeOf(deviceInfo);
// attempt to read the device info from the list, if this fails, we're at the end of the list
if (!SetupDiEnumDeviceInfo(deviceList, deviceNumber, ref deviceInfo))
{
deviceCount = deviceNumber;
break;
}
}
}
finally
{
if (deviceList != IntPtr.Zero) { SetupDiDestroyDeviceInfoList(deviceList); }
}
Console.WriteLine("Number of cores: {0}", deviceCount);
}
[DllImport("setupapi.dll", SetLastError = true)]
private static extern IntPtr SetupDiGetClassDevs(ref Guid ClassGuid,
[MarshalAs(UnmanagedType.LPStr)]String enumerator,
IntPtr hwndParent,
Int32 Flags);
[DllImport("setupapi.dll", SetLastError = true)]
private static extern Int32 SetupDiDestroyDeviceInfoList(IntPtr DeviceInfoSet);
[DllImport("setupapi.dll", SetLastError = true)]
private static extern bool SetupDiEnumDeviceInfo(IntPtr DeviceInfoSet,
Int32 MemberIndex,
ref SP_DEVINFO_DATA DeviceInterfaceData);
[StructLayout(LayoutKind.Sequential)]
private struct SP_DEVINFO_DATA
{
public int cbSize;
public Guid ClassGuid;
public uint DevInst;
public IntPtr Reserved;
}
private enum DIGCF
{
DEFAULT = 0x1,
PRESENT = 0x2,
ALLCLASSES = 0x4,
PROFILE = 0x8,
DEVICEINTERFACE = 0x10,
}
Environment.ProcessorCount
[Documentation]
WMI queries are slow, so try to Select only the desired members instead of using Select *.
The following query takes 3.4s:
foreach (var item in new System.Management.ManagementObjectSearcher("Select * from Win32_Processor").Get())
While this one takes 0.122s:
foreach (var item in new System.Management.ManagementObjectSearcher("Select NumberOfCores from Win32_Processor").Get())
Environment.ProcessorCount should give you the number of cores on the local machine.
The the easyest way = Environment.ProcessorCount
Exemple from Environment.ProcessorCount Property
using System;
class Sample
{
public static void Main()
{
Console.WriteLine("The number of processors " +
"on this computer is {0}.",
Environment.ProcessorCount);
}
}
It's rather interesting to see how .NET get this internally to say the least... It's as "simple" as below:
namespace System.Threading
{
using System;
using System.Runtime.CompilerServices;
internal static class PlatformHelper
{
private const int PROCESSOR_COUNT_REFRESH_INTERVAL_MS = 0x7530;
private static volatile int s_lastProcessorCountRefreshTicks;
private static volatile int s_processorCount;
internal static bool IsSingleProcessor
{
get
{
return (ProcessorCount == 1);
}
}
internal static int ProcessorCount
{
get
{
int tickCount = Environment.TickCount;
int num2 = s_processorCount;
if ((num2 == 0) || ((tickCount - s_lastProcessorCountRefreshTicks) >= 0x7530))
{
s_processorCount = num2 = Environment.ProcessorCount;
s_lastProcessorCountRefreshTicks = tickCount;
}
return num2;
}
}
}
}
From .NET Framework source
You can also get it with PInvoke on Kernel32.dll
The following code is coming more or less from SystemInfo.cs from System.Web source located here:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct SYSTEM_INFO
{
public ushort wProcessorArchitecture;
public ushort wReserved;
public uint dwPageSize;
public IntPtr lpMinimumApplicationAddress;
public IntPtr lpMaximumApplicationAddress;
public IntPtr dwActiveProcessorMask;
public uint dwNumberOfProcessors;
public uint dwProcessorType;
public uint dwAllocationGranularity;
public ushort wProcessorLevel;
public ushort wProcessorRevision;
}
internal static class SystemInfo
{
static int _trueNumberOfProcessors;
internal static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
internal static extern void GetSystemInfo(out SYSTEM_INFO si);
[DllImport("kernel32.dll")]
internal static extern int GetProcessAffinityMask(IntPtr handle, out IntPtr processAffinityMask, out IntPtr systemAffinityMask);
internal static int GetNumProcessCPUs()
{
if (SystemInfo._trueNumberOfProcessors == 0)
{
SYSTEM_INFO si;
GetSystemInfo(out si);
if ((int) si.dwNumberOfProcessors == 1)
{
SystemInfo._trueNumberOfProcessors = 1;
}
else
{
IntPtr processAffinityMask;
IntPtr systemAffinityMask;
if (GetProcessAffinityMask(INVALID_HANDLE_VALUE, out processAffinityMask, out systemAffinityMask) == 0)
{
SystemInfo._trueNumberOfProcessors = 1;
}
else
{
int num1 = 0;
if (IntPtr.Size == 4)
{
uint num2 = (uint) (int) processAffinityMask;
while ((int) num2 != 0)
{
if (((int) num2 & 1) == 1)
++num1;
num2 >>= 1;
}
}
else
{
ulong num2 = (ulong) (long) processAffinityMask;
while ((long) num2 != 0L)
{
if (((long) num2 & 1L) == 1L)
++num1;
num2 >>= 1;
}
}
SystemInfo._trueNumberOfProcessors = num1;
}
}
}
return SystemInfo._trueNumberOfProcessors;
}
}
There are many answers here already, but some have heavy upvotes and are incorrect.
The .NET Environment.ProcessorCount WILL return incorrect values and can fail critically if your system WMI is configured incorrectly.
If you want a RELIABLE way to count the cores, the only way is Win32 API.
Here is a C++ snippet:
#include <Windows.h>
#include <vector>
int num_physical_cores()
{
static int num_cores = []
{
DWORD bytes = 0;
GetLogicalProcessorInformation(nullptr, &bytes);
std::vector<SYSTEM_LOGICAL_PROCESSOR_INFORMATION> coreInfo(bytes / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION));
GetLogicalProcessorInformation(coreInfo.data(), &bytes);
int cores = 0;
for (auto& info : coreInfo)
{
if (info.Relationship == RelationProcessorCore)
++cores;
}
return cores > 0 ? cores : 1;
}();
return num_cores;
}
And since this is a .NET C# Question, here's the ported version:
[StructLayout(LayoutKind.Sequential)]
struct CACHE_DESCRIPTOR
{
public byte Level;
public byte Associativity;
public ushort LineSize;
public uint Size;
public uint Type;
}
[StructLayout(LayoutKind.Explicit)]
struct SYSTEM_LOGICAL_PROCESSOR_INFORMATION_UNION
{
[FieldOffset(0)] public byte ProcessorCore;
[FieldOffset(0)] public uint NumaNode;
[FieldOffset(0)] public CACHE_DESCRIPTOR Cache;
[FieldOffset(0)] private UInt64 Reserved1;
[FieldOffset(8)] private UInt64 Reserved2;
}
public enum LOGICAL_PROCESSOR_RELATIONSHIP
{
RelationProcessorCore,
RelationNumaNode,
RelationCache,
RelationProcessorPackage,
RelationGroup,
RelationAll = 0xffff
}
struct SYSTEM_LOGICAL_PROCESSOR_INFORMATION
{
public UIntPtr ProcessorMask;
public LOGICAL_PROCESSOR_RELATIONSHIP Relationship;
public SYSTEM_LOGICAL_PROCESSOR_INFORMATION_UNION ProcessorInformation;
}
[DllImport("kernel32.dll")]
static extern unsafe bool GetLogicalProcessorInformation(SYSTEM_LOGICAL_PROCESSOR_INFORMATION* buffer, out int bufferSize);
static unsafe int GetProcessorCoreCount()
{
GetLogicalProcessorInformation(null, out int bufferSize);
int numEntries = bufferSize / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
var coreInfo = new SYSTEM_LOGICAL_PROCESSOR_INFORMATION[numEntries];
fixed (SYSTEM_LOGICAL_PROCESSOR_INFORMATION* pCoreInfo = coreInfo)
{
GetLogicalProcessorInformation(pCoreInfo, out bufferSize);
int cores = 0;
for (int i = 0; i < numEntries; ++i)
{
ref SYSTEM_LOGICAL_PROCESSOR_INFORMATION info = ref pCoreInfo[i];
if (info.Relationship == LOGICAL_PROCESSOR_RELATIONSHIP.RelationProcessorCore)
++cores;
}
return cores > 0 ? cores : 1;
}
}
public static readonly int NumPhysicalCores = GetProcessorCoreCount();
One option would be to read the data from the registry.
MSDN Article On The Topic: http://msdn.microsoft.com/en-us/library/microsoft.win32.registry.localmachine(v=vs.71).aspx)
The processors, I believe can be located here, HKEY_LOCAL_MACHINE\HARDWARE\DESCRIPTION\System\CentralProcessor
private void determineNumberOfProcessCores()
{
RegistryKey rk = Registry.LocalMachine;
String[] subKeys = rk.OpenSubKey("HARDWARE").OpenSubKey("DESCRIPTION").OpenSubKey("System").OpenSubKey("CentralProcessor").GetSubKeyNames();
textBox1.Text = "Total number of cores:" + subKeys.Length.ToString();
}
I am reasonably sure the registry entry will be there on most systems.
Thought I would throw my $0.02 in.
You can use this class:
public static class CpuCores
{
private static int cores = 0;
public static int Number
{
get
{
if (cores > 0) return cores;
RegistryKey key = Registry.LocalMachine.OpenSubKey(#"SYSTEM\CurrentControlSet\Control\Class\" +
"{50127dc3-0f36-415e-a6cc-4cb3be910b65}");
if (key == null)
{
cores = Environment.ProcessorCount;
return cores;
}
string[] subkeys = key.GetSubKeyNames();
key.Close();
cores = 0;
if (subkeys != null && subkeys.Length > 0) foreach (string s in subkeys)
{
if (s.Length != 4) continue;
int n;
if (int.TryParse(s, out n) && ++n > cores) cores = n;
}
if (cores <= 0) cores = Environment.ProcessorCount;
return cores;
}
}
}
I was looking for the same thing but I don't want to install any nuget or servicepack, so I found this solution, it is pretty simple and straight forward,
using this discussion, I thought it would be so easy to run that WMIC command and get that value, here is the C# code. You only need to use System.Management namespace (and couple more standard namespaces for process and so on).
string fileName = Path.Combine(Environment.SystemDirectory, "wbem", "wmic.exe");
string arguments = #"cpu get NumberOfCores";
Process process = new Process
{
StartInfo =
{
FileName = fileName,
Arguments = arguments,
UseShellExecute = false,
CreateNoWindow = true,
RedirectStandardOutput = true,
RedirectStandardError = true
}
};
process.Start();
StreamReader output = process.StandardOutput;
Console.WriteLine(output.ReadToEnd());
process.WaitForExit();
int exitCode = process.ExitCode;
process.Close();

Categories

Resources