I know there are two articles in CodeProject (one uses WMI and the other no WMI but in C++). I tried the WMI way, not only it's slow, but it is also unreliable. So, that's why I decided not to pursue that way. I want to do it in C# through pInvoke. I tried it but got stuck in DeviceIoControl API. Can anybody give me a hint? Here is my code:
using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
namespace Chemulator.Common
{
public class HDSerialNumber
{
[StructLayout(LayoutKind.Sequential)]
private struct IDEREGS
{
public byte bFeaturesReg;
public byte bSectorCountReg;
public byte bSectorNumberReg;
public byte bCylLowReg;
public byte bCylHighReg;
public byte bDriveHeadReg;
public byte bCommandReg;
public byte bReserved;
}
[StructLayout(LayoutKind.Sequential)]
private struct SENDCMDINPARAMS
{
public Int32 cBufferSize;
public IDEREGS irDriveRegs;
public byte bDriveNumber;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public byte[] bReserved;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public Int32[] dwReserved;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
public byte[] bBuffer;
}
[StructLayout(LayoutKind.Sequential)]
private struct DRIVERSTATUS
{
public byte bDriverError;
public byte bIDEError;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] bReserved;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public Int32[] dwReserved;
}
[StructLayout(LayoutKind.Sequential)]
private struct SENDCMDOUTPARAMS
{
public Int32 cBufferSize;
public DRIVERSTATUS DriverStatus;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = IDENTIFY_BUFFER_SIZE)]
public byte[] bBuffer;
}
[StructLayout(LayoutKind.Sequential)]
private struct GETVERSIONOUTPARAMS
{
public byte bVersion;
public byte bRevision;
public byte bReserved;
public byte bIDEDeviceMap;
public Int32 fCapabilities;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public Int32 dwReserved;
}
[StructLayout(LayoutKind.Sequential)]
private struct STORAGE_PROPERTY_QUERY
{
public Int32 PropertyId;
public Int32 QueryType;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
public byte[] AdditionalParameters;
}
[StructLayout(LayoutKind.Sequential)]
private struct STORAGE_DEVICE_DESCRIPTOR
{
public Int32 Version;
public Int32 Size;
public byte DeviceType;
public byte DeviceTypeModifier;
public byte RemovableMedia;
public byte CommandQueueing;
public Int32 VendorIdOffset;
public Int32 ProductIdOffset;
public Int32 ProductRevisionOffset;
public Int32 SerialNumberOffset;
public byte BusType;
public Int32 RawPropertiesLength;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10240)]
public byte[] RawDeviceProperties;
}
[DllImport("kernel32.dll", SetLastError = true)]
private static extern SafeFileHandle CreateFile(string lpFileName, Int32 dwDesiredAccess, Int32 dwShareMode, IntPtr lpSecurityAttributes, Int32 dwCreationDisposition, Int32 dwFlagsAndAttributes, IntPtr hTemplateFile);
[DllImport("kernel32")]
private static extern bool DeviceIoControl(SafeFileHandle hDevice, uint dwIoControlCode, IntPtr lpInBuffer, uint nInBufferSize, IntPtr lpOutBuffer, uint nOutBufferSize, ref uint lpBytesReturned, IntPtr lpOverlapped);
private const Int32 OPEN_EXISTING = 3;
private const Int32 GENERIC_READ = unchecked((int)0x80000000);
private const Int32 GENERIC_WRITE = 0x40000000;
private const Int32 FILE_SHARE_READ = 0x1;
private const Int32 FILE_SHARE_WRITE = 0x2;
private const Int32 FILE_SHARE_DELETE = 0x4;
private const Int32 SMART_GET_VERSION = 0x74080;
private const Int32 SMART_RCV_DRIVE_DATA = 0x7C088;
private const Int32 ID_CMD = 0xEC;
private const Int32 IDENTIFY_BUFFER_SIZE = 512;
private const Int32 CAP_SMART_CMD = 0x4;
private const Int32 IOCTL_STORAGE_QUERY_PROPERTY = 0x2D1400;
private const Int32 PropertyStandardQuery = 0;
private const Int32 StorageDeviceProperty = 0;
public static string GetSerialNumber(int diskNumber)
{
string str = GetSerialNumberUsingStorageQuery(diskNumber);
if (string.IsNullOrEmpty(str))
str = GetSerialNumberUsingSmart(diskNumber);
return str;
}
public static string GetSerialNumberUsingStorageQuery(int diskNumber)
{
using (SafeFileHandle hDisk = OpenDisk(diskNumber))
{
uint iBytesReturned = 0;
var spq = new STORAGE_PROPERTY_QUERY();
var sdd = new STORAGE_DEVICE_DESCRIPTOR();
spq.PropertyId = StorageDeviceProperty;
spq.QueryType = PropertyStandardQuery;
if (DeviceIoControl(hDisk, IOCTL_STORAGE_QUERY_PROPERTY, spq, (uint)Marshal.SizeOf(spq), sdd, (uint)Marshal.SizeOf(sdd), ref iBytesReturned, IntPtr.Zero))
throw CreateWin32Exception(Marshal.GetLastWin32Error(), "DeviceIoControl(IOCTL_STORAGE_QUERY_PROPERTY)");
var result = new StringBuilder();
if (sdd.SerialNumberOffset > 0)
{
var rawDevicePropertiesOffset = Marshal.SizeOf(sdd) - sdd.RawDeviceProperties.Length;
int pos = sdd.SerialNumberOffset - rawDevicePropertiesOffset;
while (pos < iBytesReturned && sdd.RawDeviceProperties[pos] != 0)
{
result.Append(Encoding.ASCII.GetString(sdd.RawDeviceProperties, pos, 1));
pos += 1;
}
}
return result.ToString();
}
}
public static string GetSerialNumberUsingSmart(int diskNumber)
{
using (SafeFileHandle hDisk = OpenDisk(diskNumber))
{
if (IsSmartSupported(hDisk))
{
Int32 iBytesReturned = 0;
var sci = new SENDCMDINPARAMS();
var sco = new SENDCMDOUTPARAMS();
sci.irDriveRegs.bCommandReg = ID_CMD;
sci.bDriveNumber = (byte)diskNumber;
sci.cBufferSize = IDENTIFY_BUFFER_SIZE;
if (DeviceIoControl(hDisk, SMART_RCV_DRIVE_DATA, sci, (uint)Marshal.SizeOf(sci), sco, (uint)Marshal.SizeOf(sco), ref iBytesReturned, IntPtr.Zero))
throw CreateWin32Exception(Marshal.GetLastWin32Error(), "DeviceIoControl(SMART_RCV_DRIVE_DATA)");
var result = new StringBuilder();
for (int index = 20; index < 39; index += 2)
{
result.Append(Encoding.ASCII.GetString(sco.bBuffer, index + 1, 1));
result.Append(Encoding.ASCII.GetString(sco.bBuffer, index, 1));
}
return result.ToString();
}
return string.Empty;
}
}
private static Win32Exception CreateWin32Exception(Int32 errorCode, string context)
{
var win32Exception = new Win32Exception(errorCode);
win32Exception.Data["Context"] = context;
return win32Exception;
}
private static SafeFileHandle OpenDisk(int diskNumber)
{
SafeFileHandle hDevice = CreateFile(string.Format(#"\\.\PhysicalDrive{0}", diskNumber), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);
if (!hDevice.IsInvalid)
return hDevice;
else
throw CreateWin32Exception(Marshal.GetLastWin32Error(), "CreateFile");
}
private static bool IsSmartSupported(SafeFileHandle hDisk)
{
uint iBytesReturned = 0;
var gvo = new GETVERSIONOUTPARAMS();
IntPtr pGVO = Marshal.AllocHGlobal(512);
if (DeviceIoControl(hDisk, SMART_GET_VERSION, IntPtr.Zero, 0, pGVO, 512, ref iBytesReturned, IntPtr.Zero))
return false;
return (gvo.fCapabilities & CAP_SMART_CMD) > 0;
}
}
}
Check out the pinvoke.net tutorial about DeviceIOcontrol.
Scroll down the page where you can see VB .NET 3.0 Full Example (Thanks to "bogdandaniel") Edited by pPumkiN. It is a complete example of accessing diffferent IO devices. I beleieve there is DRIVE_INFO too.
Also i dont have any experience with this. Try it yourself
Related
I'm trying to get Informations about DVDs by ioctl in C#
the C Structure Looks like this and is working in a mixed CLR C++ Library
typedef enum {
DvdChallengeKey = 0x01,
DvdBusKey1,
DvdBusKey2,
DvdTitleKey,
DvdAsf,
DvdSetRpcKey = 0x6,
DvdGetRpcKey = 0x8,
DvdDiskKey = 0x80,
DvdInvalidateAGID = 0x3f
} DVD_KEY_TYPE;
typedef struct DVD_COPY_PROTECT_KEY
{
ULONG KeyLength;
DVD_SESSION_ID SessionId;
DVD_KEY_TYPE KeyType;
ULONG KeyFlags;
union
{
struct
{
ULONG FileHandle;
ULONG Reserved; // used for NT alignment
};
LARGE_INTEGER TitleOffset;
} Parameters;
UCHAR KeyData[0];
} DVD_COPY_PROTECT_KEY, * PDVD_COPY_PROTECT_KEY;
My C# equivalent Looks
public enum DVD_KEY_TYPE
{
DvdChallengeKey = 0x01,
DvdBusKey1,
DvdBusKey2,
DvdTitleKey,
DvdAsf,
DvdSetRpcKey = 0x6,
DvdGetRpcKey = 0x8,
DvdDiskKey = 0x80,
DvdInvalidateAGID = 0x3f
}
[StructLayout(LayoutKind.Sequential)]
public struct DVD_COPY_PROTECT_KEY
{
public uint KeyLength;
public int SessionId;
public DVD_KEY_TYPE KeyType;
public uint KeyFlags;
[MarshalAs(UnmanagedType.Struct)]
public DVD_COPY_PROTECT_KEY_Parameters Parameters;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
private byte[] KeyData;
public DVD_COPY_PROTECT_KEY(DVD_KEY_TYPE keyType, int sessionId)
{
SessionId = sessionId;
KeyType = keyType;
KeyFlags = 0;
KeyData = new byte[10];
KeyLength = 32;//GetKeyLength(this);
Parameters = new DVD_COPY_PROTECT_KEY_Parameters();
var t = Marshal.SizeOf(Parameters);
var t1 = Marshal.SizeOf(Parameters.Inner);
var t2 = Marshal.SizeOf(Parameters.TitleOffset);
var challenge = GetChallenge();
/* Get challenge from host */
for (int i = 0; i < 10; ++i)
{
KeyData[9 - i] = challenge[i];
}
}
public static byte[] GetChallenge()
{
byte[] p_challenge = new byte[10];
/* Setup a challenge, any values should work */
for (int i = 0; i < 10; ++i)
{
p_challenge[i] = (byte)i;
}
return p_challenge;
}
public static uint GetKeyLength(DVD_COPY_PROTECT_KEY dcpk)
{
int size = Marshal.SizeOf(dcpk);
switch (dcpk.KeyType)
{
case DVD_KEY_TYPE.DvdChallengeKey:
return (uint)(12 + size); //36
case DVD_KEY_TYPE.DvdBusKey1:
return (uint)(8 + size); //32
case DVD_KEY_TYPE.DvdBusKey2:
return (uint)(8 + size);
default:
return 0;
}
}
}
[StructLayout(LayoutKind.Explicit)]
public struct DVD_COPY_PROTECT_KEY_Parameters
{
[FieldOffset(0)]
public DVD_COPY_PROTECT_KEY_Parameters_Inner Inner;
[FieldOffset(0)]
public int TitleOffset;
}
[StructLayout(LayoutKind.Sequential)]
public struct DVD_COPY_PROTECT_KEY_Parameters_Inner
{
public IntPtr FileHandle;
public uint Reserved;
}
If i call DeviceIoControl i get an Exception PInvokeStackImbalance, if i use classes instead i get ErrorCode 87 from Marshal.GetLastWin32Error();
Someone any Idea?
Update
My DeviceIoControl
[System.Runtime.InteropServices.DllImport("Kernel32.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
public extern static int DeviceIoControl(IntPtr hDevice, uint IoControlCode, ref DVD_COPY_PROTECT_KEY dcpk, uint InBufferSize, ref DVD_COPY_PROTECT_KEY dcpk2, uint OutBufferSize, ref uint BytesReturned, IntPtr Overlapped);
I have add ref keywords now i get with structs no Exception but ErrorCode 87
My Code can be found here
How would you write this type of struct in c#?
struct _JOBOBJECT_BASIC_PROCESS_ID_LIST {
DWORD NumberOfAssignedProcesses;
DWORD NumberOfProcessIdsInList;
ULONG_PTR ProcessIdList[1];
}
sins there is no set size for the ProcessIdList array, what do you do? Do you just write it like this:
[StructLayout(LayoutKind.Sequential)]
struct JOBOBJECT_BASIC_PROCESS_ID_LIST
{
int NumberOfAssignedProcesses;
int NumberOfProcessIdsInList;
IntPtr ProcessIdList; //Must point to a allocated array, thanks jdweng for letting me know.
}
or do you just assign a size which is big enough, e.g.:
[StructLayout(LayoutKind.Sequential)]
struct JOBOBJECT_BASIC_PROCESS_ID_LIST
{
int NumberOfAssignedProcesses;
int NumberOfProcessIdsInList;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_PATH)]
UIntPtr[] ProcessIdList; //Works just fine, but is limited to the SizeConst.
}
This sort of structure is usually declared (there are others like this one in WLan APIs for example) :
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct JOBOBJECT_BASIC_PROCESS_ID_LIST
{
public int NumberOfAssignedProcesses;
public int NumberOfProcessIdsInList;
public IntPtr[] ProcessIdList;
public JOBOBJECT_BASIC_PROCESS_ID_LIST(IntPtr pList)
{
int nIntSize = Marshal.SizeOf<int>(); // 4
NumberOfAssignedProcesses = Marshal.ReadInt32(pList, 0);
NumberOfProcessIdsInList = Marshal.ReadInt32(pList, nIntSize);
ProcessIdList = new IntPtr[NumberOfProcessIdsInList];
for (int i = 0; i < NumberOfProcessIdsInList; i++)
{
IntPtr pItemList = IntPtr.Zero;
if (Marshal.SizeOf<IntPtr>() == 4)
pItemList = new IntPtr(pList.ToInt32() + (i * Marshal.SizeOf<IntPtr>()) + (nIntSize * 2));
else
pItemList = new IntPtr(pList.ToInt64() + (i * Marshal.SizeOf<IntPtr>()) + (nIntSize * 2));
IntPtr nPID = new IntPtr();
nPID = Marshal.ReadIntPtr(pItemList, 0);
ProcessIdList[i] = nPID;
}
}
}
A test with 5 Notepad launched and assigned to a job with JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE,
then QueryInformationJobObject to enumerate the PIDs by using this structure =>
private IntPtr hJob = IntPtr.Zero;
bool bRet = false;
hJob = CreateJobObject(IntPtr.Zero, "Test Job Object");
JOBOBJECT_EXTENDED_LIMIT_INFORMATION jbeli = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION();
jbeli.BasicLimitInformation.LimitFlags |= (JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE | JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK | JOB_OBJECT_LIMIT_BREAKAWAY_OK);
int nLength = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION));
IntPtr pJobInfo = Marshal.AllocHGlobal(nLength);
Marshal.StructureToPtr(jbeli, pJobInfo, false);
SetInformationJobObject(hJob, JOBOBJECTINFOCLASS.JobObjectExtendedLimitInformation, pJobInfo, (uint)nLength);
Marshal.FreeHGlobal(pJobInfo);
int nNbProcesses = 5;
for (int i = 0; i < nNbProcesses; i++)
{
using (Process exeProcess = new Process())
{
exeProcess.StartInfo.FileName = "notepad";
exeProcess.Start();
exeProcess.WaitForInputIdle();
IntPtr hProcess = exeProcess.Handle;
bRet = AssignProcessToJobObject(hJob, hProcess);
}
}
JOBOBJECT_BASIC_PROCESS_ID_LIST jobpil = new JOBOBJECT_BASIC_PROCESS_ID_LIST();
jobpil.NumberOfAssignedProcesses = nNbProcesses;
int nSize = Marshal.SizeOf<JOBOBJECT_BASIC_PROCESS_ID_LIST>() + (nNbProcesses - 1) * Marshal.SizeOf<IntPtr>();
IntPtr pJobpil = Marshal.AllocHGlobal(nSize);
Marshal.StructureToPtr(jobpil, pJobpil, false);
int nReturnLength = 0;
bRet = QueryInformationJobObject(hJob, JOBOBJECTINFOCLASS.JobObjectBasicProcessIdList, pJobpil, nSize, out nReturnLength);
if (bRet)
{
var processidlist = new JOBOBJECT_BASIC_PROCESS_ID_LIST(pJobpil);
foreach (var pid in processidlist.ProcessIdList)
{
Console.WriteLine("PID: {0}", pid.ToString());
}
}
else
{
int nErr = Marshal.GetLastWin32Error();
Win32Exception win32Exception = new Win32Exception(nErr);
this.Activate();
MessageBox.Show("Error: " + win32Exception.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
Marshal.FreeHGlobal(pJobpil);
// CloseHandle can be added in Form1_FormClosed :
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
CloseHandle(hJob);
}
Declarations =>
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern IntPtr CreateJobObject(IntPtr lpJobAttributes, string lpName);
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool SetInformationJobObject(IntPtr hJob, JOBOBJECTINFOCLASS JobObjectInfoClass, IntPtr lpJobObjectInfo, uint cbJobObjectInfoLength);
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool AssignProcessToJobObject(IntPtr hJob, IntPtr hProcess);
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool CloseHandle(IntPtr hObject);
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool QueryInformationJobObject(IntPtr hJob, JOBOBJECTINFOCLASS JobObjectInformationClass, [Out, MarshalAs(UnmanagedType.SysUInt)] IntPtr lpJobObjectInformation, int cbJobObjectInformationLength, out int lpReturnLength);
[StructLayout(LayoutKind.Sequential)]
struct JOBOBJECT_BASIC_LIMIT_INFORMATION
{
public ulong PerProcessUserTimeLimit;
public ulong PerJobUserTimeLimit;
public int LimitFlags;
public IntPtr MinimumWorkingSetSize;
public IntPtr MaximumWorkingSetSize;
public int ActiveProcessLimit;
public IntPtr Affinity;
public int PriorityClass;
public int SchedulingClass;
}
[StructLayout(LayoutKind.Sequential)]
struct IO_COUNTERS
{
public ulong ReadOperationCount;
public ulong WriteOperationCount;
public ulong OtherOperationCount;
public ulong ReadTransferCount;
public ulong WriteTransferCount;
public ulong OtherTransferCount;
}
[StructLayout(LayoutKind.Sequential)]
struct JOBOBJECT_EXTENDED_LIMIT_INFORMATION
{
public JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation;
public IO_COUNTERS IoInfo;
public IntPtr ProcessMemoryLimit;
public IntPtr JobMemoryLimit;
public IntPtr PeakProcessMemoryUsed;
public IntPtr PeakJobMemoryUsed;
}
//
// Basic Limits
//
public const int JOB_OBJECT_LIMIT_WORKINGSET = 0x00000001;
public const int JOB_OBJECT_LIMIT_PROCESS_TIME = 0x00000002;
public const int JOB_OBJECT_LIMIT_JOB_TIME = 0x00000004;
public const int JOB_OBJECT_LIMIT_ACTIVE_PROCESS = 0x00000008;
public const int JOB_OBJECT_LIMIT_AFFINITY = 0x00000010;
public const int JOB_OBJECT_LIMIT_PRIORITY_CLASS = 0x00000020;
public const int JOB_OBJECT_LIMIT_PRESERVE_JOB_TIME = 0x00000040;
public const int JOB_OBJECT_LIMIT_SCHEDULING_CLASS = 0x00000080;
//
// Extended Limits
//
public const int JOB_OBJECT_LIMIT_PROCESS_MEMORY = 0x00000100;
public const int JOB_OBJECT_LIMIT_JOB_MEMORY = 0x00000200;
public const int JOB_OBJECT_LIMIT_JOB_MEMORY_HIGH = JOB_OBJECT_LIMIT_JOB_MEMORY;
public const int JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION = 0x00000400;
public const int JOB_OBJECT_LIMIT_BREAKAWAY_OK = 0x00000800;
public const int JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK = 0x00001000;
public const int JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE = 0x00002000;
public const int JOB_OBJECT_LIMIT_SUBSET_AFFINITY = 0x00004000;
public const int JOB_OBJECT_LIMIT_JOB_MEMORY_LOW = 0x00008000;
public enum JOBOBJECTINFOCLASS
{
JobObjectBasicAccountingInformation = 1,
JobObjectBasicLimitInformation,
JobObjectBasicProcessIdList,
JobObjectBasicUIRestrictions,
JobObjectSecurityLimitInformation, // deprecated
JobObjectEndOfJobTimeInformation,
JobObjectAssociateCompletionPortInformation,
JobObjectBasicAndIoAccountingInformation,
JobObjectExtendedLimitInformation,
JobObjectJobSetInformation,
JobObjectGroupInformation,
JobObjectNotificationLimitInformation,
JobObjectLimitViolationInformation,
JobObjectGroupInformationEx,
JobObjectCpuRateControlInformation,
JobObjectCompletionFilter,
JobObjectCompletionCounter,
JobObjectReserved1Information = 18,
JobObjectReserved2Information,
JobObjectReserved3Information,
JobObjectReserved4Information,
JobObjectReserved5Information,
JobObjectReserved6Information,
JobObjectReserved7Information,
JobObjectReserved8Information,
JobObjectReserved9Information,
JobObjectReserved10Information,
JobObjectReserved11Information,
JobObjectReserved12Information,
JobObjectReserved13Information,
JobObjectReserved14Information = 31,
JobObjectNetRateControlInformation,
JobObjectNotificationLimitInformation2,
JobObjectLimitViolationInformation2,
JobObjectCreateSilo,
JobObjectSiloBasicInformation,
JobObjectReserved15Information = 37,
JobObjectReserved16Information,
JobObjectReserved17Information,
JobObjectReserved18Information,
JobObjectReserved19Information = 41,
JobObjectReserved20Information,
MaxJobObjectInfoClass
}
I think any of the ways you mentioned should work.
In addition, there is a matching feature in c#: Define an array with the fixed keyword:
struct JOBOBJECT_BASIC_PROCESS_ID_LIST
{
int NumberOfAssignedProcesses;
int NumberOfProcessIdsInList;
fixed IntPtr ProcessIdList[1];
}
See documentation:
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/unsafe-code-pointers/fixed-size-buffers
Also no bounds check, so you should be able to read behind the end of the struckt easily:
Note
Except for memory created by using stackalloc, the C# compiler and the common language runtime (CLR) do not perform any security buffer overrun checks. As with all unsafe code, use caution.
I have a C# application which controls and monitors a PMAC controller. This application should be able to run for a few days at least, but I see that its memory usage would increase all the time. At first the memory usage is about 230M, and it will increase with 25M each hour.
I have found that memory does not increase unless I call the ReadDataFromDPRam() method.
I call this method 10msec intervals.
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct PmacServoRead
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)MotorNo.All)]
public float[] CurPosition; // M4000,
[MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)MotorNo.All)]
public float[] CurVelocity;
public int AmpEnable;
public int PosLimit;
public int NegLimit;
public int HomeComp;
public int DesiredVelocityZero;
...
}
[DllImport("Pcomm32.dll")]
public static extern IntPtr PmacDPRGetMem(UInt32 dwDevice, UInt32 offset, UInt32 count, IntPtr val);
public IntPtr GetDpramMemory(UInt32 devNo, UInt32 offset, UInt32 count, IntPtr val)
{
return PmacDPRGetMem(devNo, offset, count, val);
}
private PmacServoRead m_PmacServoRead = new PmacServoRead();
private PmacInput m_PmacInput = new PmacInput();
int m_ReadSize = Marshal.SizeOf(typeof(PmacServoRead));
int m_ReadSizeDi = Marshal.SizeOf(typeof(PmacInput));
private int ReadDataFromDPRam()
{
if (IsOpen == true)
{
IntPtr ptr1 = Marshal.AllocHGlobal(m_ReadSize);
GetDpramMemory(DeviceNo, CcpPmacComm.DpramReadOffset, (uint)m_ReadSize, ptr1);
m_PmacServoRead =(PmacServoRead)Marshal.PtrToStructure(ptr1, typeof(PmacServoRead));
Marshal.DestroyStructure(ptr1, typeof(PmacServoRead));
Marshal.FreeHGlobal(ptr1);
ptr1 = Marshal.AllocHGlobal(m_ReadSizeDi);
GetDpramMemory(DeviceNo, CcpPmacComm.DpramInputReadOffset, (uint)m_ReadSizeDi, ptr1);
m_PmacInput = (PmacInput)Marshal.PtrToStructure(ptr1, typeof(PmacInput));
Marshal.DestroyStructure(ptr1, typeof(PmacInput));
Marshal.FreeHGlobal(ptr1);
}
return -1;
}
Please help me.
i have a some problem on getting digital signature of the file in silverlight.
I`am using crypt32.dll functions to get signed hash , but i getting confused with unexpected error as a result of CryptSignMessage method - "parametr is incorrect".
Here is my code:
public byte[] SignData(IntPtr certContext, string signingText)
{
IntPtr buffer = IntPtr.Zero;
Crypt32.CRYPT_SIGN_MESSAGE_PARA param = new Crypt32.CRYPT_SIGN_MESSAGE_PARA();
Byte[] result = null;
try
{
byte[] data = System.Text.Encoding.Unicode.GetBytes(signingText);
IntPtr[] rgpbToBeSigned = new IntPtr[1];
int[] rgcbToBeSigned = new int[1];
IntPtr pSignerCert = certContext;
buffer = Ole32.CoTaskMemAlloc((uint)(Marshal.SizeOf(data[0]) * data.Length));
Marshal.Copy(data, 0, buffer, data.Length);
rgpbToBeSigned[0] = buffer;
rgcbToBeSigned[0] = 1;
int resultlength = 0;
param.dwMsgEncodingType = Crypt32.Constants.X509_ASN_ENCODING;
param.pSigningCert = certContext;
param.cbSize = Marshal.SizeOf(param);
param.HashAlgorithm.pszObjId = "1.2.643.2.2.9";
param.HashAlgorithm.Parameters.cbData = 0;
param.HashAlgorithm.Parameters.pbData = null;
param.pvHashAuxInfo = IntPtr.Zero;
param.cMsgCert = 1;
param.rgpMsgCert = kernel32.GlobalAlloc(0, (UIntPtr)(IntPtr.Size));
Marshal.StructureToPtr(certContext, param.rgpMsgCert, false);
if (Crypt32.CryptSignMessage(ref param, true, (int)1, rgpbToBeSigned, rgcbToBeSigned, result, ref resultlength) == false)
throw new DB_Win32Exception(); //throws a string with error message from Getlastresult()
}
finally
{
if (!(param.rgpMsgCert == IntPtr.Zero))
kernel32.LocalFree(param.rgpMsgCert);
if (!(buffer == IntPtr.Zero))
Ole32.CoTaskMemFree(buffer);
}
Here is my external method declaration:
[DllImport("Crypt32.dll", SetLastError = true)]
public static extern Boolean CryptSignMessage(
ref CRYPT_SIGN_MESSAGE_PARA pSignPara,
Boolean fDetachedSignature,
Int32 cToBeSigned,
IntPtr[] rgpbToBeSigned,
Int32[] rgcbToBeSigned,
Byte[] pbSignedBlob,
ref Int32 pcbSignedBlob
);
[StructLayout(LayoutKind.Sequential)]
public struct CRYPT_ALGORITHM_IDENTIFIER
{
[MarshalAs(UnmanagedType.LPStr, SizeConst = 100)] //???
public String pszObjId;
public CRYPTOAPI_BLOB Parameters;
}
[StructLayout(LayoutKind.Sequential)]
public struct CRYPT_SIGN_MESSAGE_PARA
{
public Int32 cbSize;
public Int32 dwMsgEncodingType;
public IntPtr pSigningCert;
public CRYPT_ALGORITHM_IDENTIFIER HashAlgorithm;
public IntPtr pvHashAuxInfo;
public Int32 cMsgCert;
public IntPtr rgpMsgCert;
public Int32 cMsgCrl;
public IntPtr rgpMsgCrl;
public Int32 cAuthAttr;
public IntPtr rgAuthAttr;
public Int32 cUnauthAttr;
public IntPtr rgUnauthAttr;
public Int32 dwFlags;
public Int32 dwInnerContentType;
}
public struct CRYPTOAPI_BLOB
{
public Int32 cbData;
[MarshalAs(UnmanagedType.ByValArray,SizeConst=999)] // ???
public Byte[] pbData;
}
Does anybody knows how i can determine where is the poblem?
I'm trying to read raw disk. I've successfully opened the drive and obtained valid handle (CreateFile), set offset for that handle to zero (SetFilePointerEx) and read the data to a buffer Byte[] (ReadFile). So far so good. But for some unknown reason, when I compare the buffer (took my a while to figure it out actually) to what 3rd party utilities (Disk Investigator) shows. It doesn't contain a boot information (jump instruction), but correct disk data, but starting at offset 85 = 0x55. So somewhere in the middle of volume boot information.
Why is that? Is there something, I'm missing (obviously I am)?
System: Windows 8 (in VmWare Workstation)
Code:
// moves the pointer to a given offset
Int64 offset = 0;
Int64 newOffset;
Int32 bufferSize = (Int32) clusterSizeInBytes;
SetFilePointerEx(driveHandle.Handle, offset, out newOffset, WinMoveMethod.Begin);
Int32 error = Marshal.GetLastWin32Error();
// reads the raw buffer
Int32 numberOfBytesRead;
rawData = new Byte[bufferSize];
Boolean result = ReadFile(driveHandle.Handle, rawData, bufferSize,
out numberOfBytesRead, IntPtr.Zero);
CreateFile (elsewhere)
driveHandle = CreateFile("\\.\PhysicalDrive1", WinFileAccessMode.GenericRead,
WinFileSharedAccess.All, IntPtr.Zero, WinFileMode.OpenExisting,
WinFileAttribute.None, IntPtr.Zero);
PInvoke methods:
[DllImport("kernel32.dll", SetLastError = true)]
public static extern Boolean SetFilePointerEx(
[In] SafeFileHandle fileHandle,
[In] Int64 distanceToMove,
[Out] out Int64 newOffset,
[In] WinMoveMethod moveMethod);
[DllImport("kernel32", SetLastError = true)]
public extern static Boolean ReadFile(
[In] SafeFileHandle handle,
[Out] Byte[] buffer,
[In] Int32 numBytesToRead,
[Out] out Int32 numBytesRead,
[In] IntPtr overlapped);
Enumerations:
public enum WinMoveMethod : uint
{
Begin = 0,
Current = 1,
End = 2
}
Can't find anymore a library using a namespace "DiskLib". I can't test that or completely upload now, even I don't know anymore who wrote that piece of code, but the lines you may find interesting are
public class DiskStream : Stream
{
public const int DEFAULT_SECTOR_SIZE = 512;
private const int BUFFER_SIZE = 4096;
private string diskID;
private DiskInfo diskInfo;
private FileAccess desiredAccess;
private SafeFileHandle fileHandle;
public DiskInfo DiskInfo
{
get { return this.diskInfo; }
}
public uint SectorSize
{
get { return this.diskInfo.BytesPerSector; }
}
public DiskStream(string diskID, FileAccess desiredAccess)
{
this.diskID = diskID;
this.diskInfo = new DiskInfo(diskID);
this.desiredAccess = desiredAccess;
// if desiredAccess is Write or Read/Write
// find volumes on this disk
// lock the volumes using FSCTL_LOCK_VOLUME
// unlock the volumes on Close() or in destructor
this.fileHandle = this.openFile(diskID, desiredAccess);
}
private SafeFileHandle openFile(string id, FileAccess desiredAccess)
{
uint access;
switch (desiredAccess)
{
case FileAccess.Read:
access = DeviceIO.GENERIC_READ;
break;
case FileAccess.Write:
access = DeviceIO.GENERIC_WRITE;
break;
case FileAccess.ReadWrite:
access = DeviceIO.GENERIC_READ | DeviceIO.GENERIC_WRITE;
break;
default:
access = DeviceIO.GENERIC_READ;
break;
}
SafeFileHandle ptr = DeviceIO.CreateFile(
id,
access,
DeviceIO.FILE_SHARE_READ,
IntPtr.Zero,
DeviceIO.OPEN_EXISTING,
DeviceIO.FILE_FLAG_NO_BUFFERING | DeviceIO.FILE_FLAG_WRITE_THROUGH,
IntPtr.Zero);
if (ptr.IsInvalid)
{
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
}
return ptr;
}
public override bool CanRead
{
get
{
return (this.desiredAccess == FileAccess.Read || this.desiredAccess == FileAccess.ReadWrite) ? true : false;
}
}
public override bool CanWrite
{
get
{
return (this.desiredAccess == FileAccess.Write || this.desiredAccess == FileAccess.ReadWrite) ? true : false;
}
}
public override bool CanSeek
{
get
{
return true;
}
}
public override long Length {
get { return (long)this.Length; }
}
public ulong LengthU
{
get { return this.diskInfo.Size; }
}
public override long Position {
get {
return (long)PositionU;
}
set {
PositionU = (ulong)value;
}
}
public ulong PositionU
{
get
{
ulong n = 0;
if (!DeviceIO.SetFilePointerEx(this.fileHandle, 0, out n, (uint)SeekOrigin.Current))
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
return n;
}
set
{
if (value > (this.LengthU - 1))
throw new EndOfStreamException("Cannot set position beyond the end of the disk.");
ulong n = 0;
if (!DeviceIO.SetFilePointerEx(this.fileHandle, value, out n, (uint)SeekOrigin.Begin))
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
}
}
public override void Flush()
{
// not required, since FILE_FLAG_WRITE_THROUGH and FILE_FLAG_NO_BUFFERING are used
//if (!Unmanaged.FlushFileBuffers(this.fileHandle))
// Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
}
public override void Close()
{
if (this.fileHandle != null) {
DeviceIO.CloseHandle(this.fileHandle);
this.fileHandle.SetHandleAsInvalid();
this.fileHandle = null;
}
base.Close();
}
public override void SetLength(long value)
{
throw new NotSupportedException("Setting the length is not supported with DiskStream objects.");
}
public override int Read(byte[] buffer, int offset, int count) {
return (int)Read(buffer, (uint)offset, (uint)count);
}
public unsafe uint Read(byte[] buffer, uint offset, uint count)
{
uint n = 0;
fixed (byte* p = buffer)
{
if (!DeviceIO.ReadFile(this.fileHandle, p + offset, count, &n, IntPtr.Zero))
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
}
return n;
}
public override void Write(byte[] buffer, int offset, int count) {
Write(buffer, (uint)offset, (uint)count);
}
public unsafe void Write(byte[] buffer, uint offset, uint count)
{
uint n = 0;
fixed (byte* p = buffer)
{
if (!DeviceIO.WriteFile(this.fileHandle, p + offset, count, &n, IntPtr.Zero))
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
}
}
public override long Seek(long offset, SeekOrigin origin) {
return (long)SeekU((ulong)offset, origin);
}
public ulong SeekU(ulong offset, SeekOrigin origin)
{
ulong n = 0;
if (!DeviceIO.SetFilePointerEx(this.fileHandle, offset, out n, (uint)origin))
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
return n;
}
public uint ReadSector(DiskSector sector)
{
return this.Read(sector.Data, 0, sector.SectorSize);
}
public void WriteSector(DiskSector sector)
{
this.Write(sector.Data, 0, sector.SectorSize);
}
public void SeekSector(DiskSector sector)
{
this.Seek(sector.Offset, SeekOrigin.Begin);
}
}
The DeviceIO class is a p/invoke boilerplate for Win32 API.
The DiskInfo class is a wrapper to WMI Win32_DiskDrive and Win32_DiskPartition classes.
I used that library once to clone a disk (on Win7). Hope that helps to find the solution.
For completeness and because of the details, the DeviceIO class is throughout using unsigned integers:
/// <summary>
/// P/Invoke wrappers around Win32 functions and constants.
/// </summary>
internal partial class DeviceIO
{
#region Constants used in unmanaged functions
public const uint FILE_SHARE_READ = 0x00000001;
public const uint FILE_SHARE_WRITE = 0x00000002;
public const uint FILE_SHARE_DELETE = 0x00000004;
public const uint OPEN_EXISTING = 3;
public const uint GENERIC_READ = (0x80000000);
public const uint GENERIC_WRITE = (0x40000000);
public const uint FILE_FLAG_NO_BUFFERING = 0x20000000;
public const uint FILE_FLAG_WRITE_THROUGH = 0x80000000;
public const uint FILE_READ_ATTRIBUTES = (0x0080);
public const uint FILE_WRITE_ATTRIBUTES = 0x0100;
public const uint ERROR_INSUFFICIENT_BUFFER = 122;
#endregion
#region Unamanged function declarations
[DllImport("kernel32.dll", SetLastError = true)]
public static unsafe extern SafeFileHandle CreateFile(
string FileName,
uint DesiredAccess,
uint ShareMode,
IntPtr SecurityAttributes,
uint CreationDisposition,
uint FlagsAndAttributes,
IntPtr hTemplateFile);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool CloseHandle(SafeFileHandle hHandle);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool DeviceIoControl(
SafeFileHandle hDevice,
uint dwIoControlCode,
IntPtr lpInBuffer,
uint nInBufferSize,
[Out] IntPtr lpOutBuffer,
uint nOutBufferSize,
ref uint lpBytesReturned,
IntPtr lpOverlapped);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern unsafe bool WriteFile(
SafeFileHandle hFile,
byte* pBuffer,
uint NumberOfBytesToWrite,
uint* pNumberOfBytesWritten,
IntPtr Overlapped);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern unsafe bool ReadFile(
SafeFileHandle hFile,
byte* pBuffer,
uint NumberOfBytesToRead,
uint* pNumberOfBytesRead,
IntPtr Overlapped);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool SetFilePointerEx(
SafeFileHandle hFile,
ulong liDistanceToMove,
out ulong lpNewFilePointer,
uint dwMoveMethod);
[DllImport("kernel32.dll")]
public static extern bool FlushFileBuffers(
SafeFileHandle hFile);
#endregion
}