Detecting Audio Input & output devices connected to system - c#

I want to findout how many audio input and output devices connected to my system in C#.net
Please suggest any.
Thanks.

You need to access the necessary Windows API functions.
This class should get you started - Win32.GetSoundDevices returns a list of device names. Look up WAVEOUTCAPS in the Windows SDK for details of the other information you can get.
public class Win32 {
[DllImport("winmm.dll", SetLastError=true)]
static extern uint waveOutGetNumDevs();
[DllImport("winmm.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern uint waveOutGetDevCaps(uint hwo,ref WAVEOUTCAPS pwoc,uint cbwoc);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct WAVEOUTCAPS {
public ushort wMid;
public ushort wPid;
public uint vDriverVersion;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string szPname;
public uint dwFormats;
public ushort wChannels;
public ushort wReserved1;
public uint dwSupport;
}
public static string [] GetSoundDevices() {
uint devices = waveOutGetNumDevs();
string [] result = new string[devices];
WAVEOUTCAPS caps = new WAVEOUTCAPS();
for(uint i = 0; i < devices; i++) {
waveOutGetDevCaps(i, ref caps, (uint)Marshal.SizeOf(caps));
result[i] = caps.szPname;
}
return result;
}
}

Related

Can't read privileges from process access token

I'm trying to get the list of groups and privileges in a process access token and some info about them (name, flags and description).
To do this I'm using the GetTokenInfomation function and the TOKEN_GROUPS_AND_PRIVILEGES structure.
These are the structure definitions:
TOKEN_GROUPS_AND_PRIVILEGES
[StructLayout(LayoutKind.Sequential)]
public struct TOKEN_GROUPS_AND_PRIVILEGES
{
public uint SidCount;
public uint SidLength;
public IntPtr Sids;
public uint RestrictedSidCount;
public uint RestrictedSidLength;
public IntPtr RestrictedSids;
public uint PrivilegeCount;
public uint PrivilegeLength;
public IntPtr Privileges;
public LUID AuthenticationID;
}
LUID_AND_ATTRIBUTES
[StructLayout(LayoutKind.Sequential)]
public struct LUID_AND_ATTRIBUTES
{
public LUID Luid;
public uint Attributes;
}
LUID
[StructLayout(LayoutKind.Sequential)]
public struct LUID
{
public uint LowPart;
public int HighPart;
}
I can read the groups SIDs and get info on them fine but when I try to read the privileges I always get an Access violation.
This is the code that I use to read the privileges:
for (int i = 0; i < GroupsAndPrivilegesInfo.PrivilegeCount; i++)
{
Privilege = (Win32Structures.LUID_AND_ATTRIBUTES)Marshal.PtrToStructure(GroupsAndPrivilegesInfo.Privileges, typeof(Win32Structures.LUID_AND_ATTRIBUTES));
PrivilegeName = GetPrivilegeName(Privilege.Luid) ?? "Non disponibile";
PrivilegeStatus = GetPrivilegeFlags((Win32Enumerations.PrivilegeLUIDAttribute)Privilege.Attributes) ?? "Non disponibile";
PrivilegeDescription = GetPrivilegeDescription(PrivilegeName) ?? "Non disponibile";
Privileges.Add(new TokenPrivilegeInfo(PrivilegeName, PrivilegeStatus, PrivilegeDescription));
GroupsAndPrivilegesInfo.Privileges += Marshal.SizeOf(typeof(Win32Structures.LUID_AND_ATTRIBUTES));
}
The exception occurs when calling the GetPrivilegeName method which uses the function LookupPrivilegeNameW defined as follows:
[DllImport("Advapi32.dll", EntryPoint = "LookupPrivilegeNameW", CharSet = CharSet.Unicode, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool LookupPrivilegeName(string SystemName, Win32Structures.LUID LUID, StringBuilder PrivilegeName, ref uint NameLength);
I tried different methods to read the data such as:
Manually calculating the offset to the privileges array element from the start of the structure
Declare the privileges field as an array and set a SizeConst to an obviously oversized value
Even those methods threw an Access violation exception.
I don't undestand what is the problem given that I use the same code to read the SIDs and it works normally.
First, The second parameter of LookupPrivilegeNameW is A pointer to a LUID. You need to declare it as a reference type like ref Win32Structures.LUID LUID.
And then the TOKEN_GROUPS_AND_PRIVILEGES.Privileges is an array of the privileges.
Your code does not retrieve all Privileges, but repeatedly reads the first Privilege every time.
Here is the working sample:
namespace ConsoleApp2
{
class Program
{
[StructLayout(LayoutKind.Sequential)]
public struct TOKEN_GROUPS_AND_PRIVILEGES
{
public uint SidCount;
public uint SidLength;
public IntPtr Sids;
public uint RestrictedSidCount;
public uint RestrictedSidLength;
public IntPtr RestrictedSids;
public uint PrivilegeCount;
public uint PrivilegeLength;
public IntPtr Privileges;
public LUID AuthenticationID;
}
[StructLayout(LayoutKind.Sequential)]
public struct LUID_AND_ATTRIBUTES
{
public LUID Luid;
public uint Attributes;
}
[StructLayout(LayoutKind.Sequential)]
public struct LUID
{
public uint LowPart;
public int HighPart;
}
public enum TOKEN_INFORMATION_CLASS
{
TokenUser = 1,
TokenGroups,
TokenPrivileges,
TokenOwner,
TokenPrimaryGroup,
TokenDefaultDacl,
TokenSource,
TokenType,
TokenImpersonationLevel,
TokenStatistics,
TokenRestrictedSids,
TokenSessionId,
TokenGroupsAndPrivileges,
TokenSessionReference,
TokenSandBoxInert,
TokenAuditPolicy,
TokenOrigin
}
[DllImport("Advapi32.dll", EntryPoint = "LookupPrivilegeNameW", CharSet = CharSet.Unicode, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool LookupPrivilegeName(string SystemName, ref LUID LUID, StringBuilder PrivilegeName, ref uint NameLength);
[DllImport("advapi32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool OpenProcessToken(IntPtr ProcessHandle,
UInt32 DesiredAccess, out IntPtr TokenHandle);
[DllImport("kernel32.dll")]
public static extern IntPtr GetCurrentProcess();
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool GetTokenInformation(IntPtr TokenHandle,
TOKEN_INFORMATION_CLASS TokenInformationClass,
IntPtr TokenInformation,
Int32 TokenInformationLength,
out Int32 ReturnLength);
public static UInt32 TOKEN_QUERY = 0x0008;
static void Main(string[] args)
{
bool ret = false;
IntPtr token;
ret = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, out token);
Int32 ReturnLength;
ret = GetTokenInformation(token, TOKEN_INFORMATION_CLASS.TokenGroupsAndPrivileges, IntPtr.Zero, 0, out ReturnLength);
IntPtr pGroupsAndPrivilegesInfo = Marshal.AllocHGlobal(ReturnLength);
ret = GetTokenInformation(token, TOKEN_INFORMATION_CLASS.TokenGroupsAndPrivileges, pGroupsAndPrivilegesInfo, ReturnLength, out ReturnLength);
TOKEN_GROUPS_AND_PRIVILEGES GroupsAndPrivilegesInfo = (TOKEN_GROUPS_AND_PRIVILEGES)Marshal.PtrToStructure(pGroupsAndPrivilegesInfo, typeof(TOKEN_GROUPS_AND_PRIVILEGES));
for (int i = 0; i < GroupsAndPrivilegesInfo.PrivilegeCount; i++)
{
//IntPtr ptr = GroupsAndPrivilegesInfo.Privileges + i * Marshal.SizeOf(typeof(LUID_AND_ATTRIBUTES));
LUID_AND_ATTRIBUTES Privilege = (LUID_AND_ATTRIBUTES)Marshal.PtrToStructure(GroupsAndPrivilegesInfo.Privileges + i * Marshal.SizeOf(typeof(LUID_AND_ATTRIBUTES)), typeof(LUID_AND_ATTRIBUTES));
StringBuilder name = new StringBuilder(50);
uint cchName = 50;
ret = LookupPrivilegeName(null, ref Privilege.Luid, name, ref cchName);
Console.WriteLine(name);
}
Marshal.FreeHGlobal(pGroupsAndPrivilegesInfo);
}
}
}

Getting Symbols from debugged process MainModule

I started writing a debugger in C#, to debug any process on my operating system. For now, it only can handle breakpoints (HW, SW, and Memory), but now I wanted to show the opcode of the process.
My first attempt was with nidsasm (NASM), but this is not suitable, because after startup a.Net Application assembler instructions are different from ndisasm (tested with CheatEngine).
So I searched a while and found some methods from the dbghelp.dll which can be called to list all loaded modules and symbols (plus the base address). Ok, my attempt is, to disassemble all modules separately with SharpDisasm.
I use ProcessModuleCollection modules = ProcessData.Instance.MPMR.ReadProcess.Modules; to get all loaded modules of the process. This works perfectly.
Now I tried to load the symbols of the MainModule, but at this point, I stuck with the implementation. I implemented the SymEnumSymbols Function with p/Invoke and other necessary functions like SymInitialize.
When I call it with a BaseAddress of for example the "User32.dll", all symbols are printed perfectly, but for the MainModule, I didn't get any symbols.
This is a screenshot from CheatEngine:
Symbols gained from Cheat Engine
As you can see, there are symbols like "Form1_Load", which I don't get with my implementation.
This is the necessary code sample:
if (!DebugApi.SymInitialize(ProcessData.Instance.MPMR.M_hProcess, null, false))
{
var err = Marshal.GetLastWin32Error();
//throw new Exception("GetMemoryInfo failed : GetLastError() : " + new Win32Exception(err).Message);
Console.WriteLine("GetMemoryInfo failed : GetLastError() : " + new Win32Exception(err).Message);
return;
}
if (!DebugApi.SymEnumSymbols(ProcessData.Instance.MPMR.M_hProcess, (ulong)ProcessData.Instance.MPMR.ReadProcess.MainModule.BaseAddress, "!", DebugApi.EnumSyms, IntPtr.Zero))
{
var err = Marshal.GetLastWin32Error();
//throw new Exception("GetMemoryInfo failed : GetLastError() : " + new Win32Exception(err).Message);
Console.WriteLine("GetMemoryInfo failed : GetLastError() : " + new Win32Exception(err).Message);
return;
}
DebugApi.SymCleanup(ProcessData.Instance.MPMR.M_hProcess);
And my DebugApi, with all necessary p/Invoke functions.
public class DebugApi
{
[DllImport("dbghelp.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SymInitialize(IntPtr hProcess, string UserSearchPath, [MarshalAs(UnmanagedType.Bool)]bool fInvadeProcess);
[DllImport("dbghelp.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SymCleanup(IntPtr hProcess);
[DllImport("dbghelp.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern ulong SymLoadModuleEx(IntPtr hProcess, IntPtr hFile, string ImageName, string ModuleName, long BaseOfDll, int DllSize, IntPtr Data, int Flags);
[DllImport("dbghelp.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SymEnumSymbols(IntPtr hProcess, ulong BaseOfDll, string Mask, PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback, IntPtr UserContext);
public delegate bool PSYM_ENUMERATESYMBOLS_CALLBACK(ref SYMBOL_INFO pSymInfo, uint SymbolSize, IntPtr UserContext);
public static bool EnumSyms(ref SYMBOL_INFO pSymInfo, uint SymbolSize, IntPtr UserContext)
{
Console.Out.WriteLine("Name: " + pSymInfo.Name);
return true;
}
[Flags]
public enum SymFlag : uint
{
VALUEPRESENT = 0x00000001,
REGISTER = 0x00000008,
REGREL = 0x00000010,
FRAMEREL = 0x00000020,
PARAMETER = 0x00000040,
LOCAL = 0x00000080,
CONSTANT = 0x00000100,
EXPORT = 0x00000200,
FORWARDER = 0x00000400,
FUNCTION = 0x00000800,
VIRTUAL = 0x00001000,
THUNK = 0x00002000,
TLSREL = 0x00004000,
}
[Flags]
public enum SymTagEnum : uint
{
Null,
Exe,
Compiland,
CompilandDetails,
CompilandEnv,
Function,
Block,
Data,
Annotation,
Label,
PublicSymbol,
UDT,
Enum,
FunctionType,
PointerType,
ArrayType,
BaseType,
Typedef,
BaseClass,
Friend,
FunctionArgType,
FuncDebugStart,
FuncDebugEnd,
UsingNamespace,
VTableShape,
VTable,
Custom,
Thunk,
CustomType,
ManagedType,
Dimension
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct SYMBOL_INFO
{
public uint SizeOfStruct;
public uint TypeIndex;
public ulong Reserved1;
public ulong Reserved2;
public uint Reserved3;
public uint Size;
public ulong ModBase;
public SymFlag Flags;
public ulong Value;
public ulong Address;
public uint Register;
public uint Scope;
public SymTagEnum Tag;
public int NameLen;
public int MaxNameLen;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
public string Name;
}
}
My Functions should be ok, because it works with other Modules (loaded dll's for example). Maybe I don't understand the concept of symbols of a .Net Executable or missing something.
can it be that you are looking for System.Diagnostics.SymbolStore.ISymbolScope.
Have a look at the class SymbolAccess, you can use it to gain access to ISymbolScope.GetLocals() that returns ISymbolVariable[] and GetChildren() again returning in this time an array called ISymbolVariable[]
Now another interesting set of reference code samples is the Debugger extension lets you "snif" the values as shown here

c# How to use the new Version Helper API

Since OSVersion is now not reliable since Windows 10 has been released (this function reports Windows 8 for Windows 10), I'm attempting to use the new Version Helper API functions in my C# application. Here they are.
I apologize if this is simply a issue with my DLL import, but here is my attempt to pull in these new methods to detect the OS correctly.
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern bool IsWindows7OrGreater();
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern bool IsWindows8OrGreater();
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern bool IsWindows8Point1OrGreater();
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern bool IsWindows10OrGreater();
Whenever I'm calling these methods, I'm getting:
Exception is: EntryPointNotFoundException - Unable to find an entry point named 'IsWindows7OrGreater' in DLL 'kernel32.dll'.
Am I doing something wrong? Anyone have any ideas? Thanks for any help!
EDIT: Please see the accepted answer and take a look at this code project for a good start on porting these methods over to C#.
Your code must have a Manifest that contains
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- A list of all Windows versions that this application is designed to work with. Windows will automatically select the most compatible environment.-->
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<!-- Windows Vista -->
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
<!-- If your application is designed to work with Windows 7, uncomment the following supportedOS node-->
<!--<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>-->
</application>
</compatibility>
This tells the OS your code supports the newer OS
Use the following class
using System;
using System.Runtime.InteropServices;
namespace VersionHelper
{
public static class VersionHelper
{
const byte VER_EQUAL = 1;
const byte VER_GREATER = 2;
const byte VER_GREATER_EQUAL = 3;
const byte VER_LESS = 4;
const byte VER_LESS_EQUAL = 5;
const byte VER_AND = 6;
const byte VER_OR = 7;
const byte VER_CONDITION_MASK = 7;
const byte VER_NUM_BITS_PER_CONDITION_MASK = 3;
//
// RtlVerifyVersionInfo() type mask bits
//
const uint VER_MINORVERSION = 0x0000001;
const uint VER_MAJORVERSION = 0x0000002;
const uint VER_BUILDNUMBER = 0x0000004;
const uint VER_PLATFORMID = 0x0000008;
const uint VER_SERVICEPACKMINOR = 0x0000010;
const uint VER_SERVICEPACKMAJOR = 0x0000020;
const uint VER_SUITENAME = 0x0000040;
const uint VER_PRODUCT_TYPE = 0x0000080;
// wProductType
// Any additional information about the system.This member can be one of the following values.
const byte VER_NT_DOMAIN_CONTROLLER = 0x0000002;
const byte VER_NT_SERVER = 0x0000003;
const byte VER_NT_WORKSTATION = 0x0000001;
//
// _WIN32_WINNT version constants
//
const ushort _WIN32_WINNT_NT4 = 0x0400;
const ushort _WIN32_WINNT_WIN2K = 0x0500;
const ushort _WIN32_WINNT_WINXP = 0x0501;
const ushort _WIN32_WINNT_WS03 = 0x0502;
const ushort _WIN32_WINNT_WIN6 = 0x0600;
const ushort _WIN32_WINNT_VISTA = 0x0600;
const ushort _WIN32_WINNT_WS08 = 0x0600;
const ushort _WIN32_WINNT_LONGHORN = 0x0600;
const ushort _WIN32_WINNT_WIN7 = 0x0601;
const ushort _WIN32_WINNT_WIN8 = 0x0602;
const ushort _WIN32_WINNT_WINBLUE = 0x0603;
const ushort _WIN32_WINNT_WINTHRESHOLD = 0x0A00; /* ABRACADABRA_THRESHOLD*/
const ushort _WIN32_WINNT_WIN10 = 0x0A00; /* ABRACADABRA_THRESHOLD*/
const bool FALSE = false;
static byte LOBYTE(ushort w)
{
return ((byte)(w & 0xff));
}
static byte HIBYTE(ushort w)
{
return ((byte)(w >> 8 & 0xff));
}
[DllImport("kernel32.dll")]
static extern ulong VerSetConditionMask(ulong ConditionMask, uint TypeMask, byte Condition );
[DllImport("kernel32.dll")]
static extern bool VerifyVersionInfoW(ref OSVERSIONINFOEXW lpVersionInformation, uint dwTypeMask, ulong dwlConditionMask);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
struct OSVERSIONINFOEXW
{
public int dwOSVersionInfoSize;
public int dwMajorVersion;
public int dwMinorVersion;
public int dwBuildNumber;
public int dwPlatformId;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string szCSDVersion;
public UInt16 wServicePackMajor;
public UInt16 wServicePackMinor;
public UInt16 wSuiteMask;
public byte wProductType;
public byte wReserved;
}
public static bool
IsWindowsVersionOrGreater(ushort wMajorVersion, ushort wMinorVersion, ushort wServicePackMajor)
{
var osvi = new OSVERSIONINFOEXW
{
dwOSVersionInfoSize = Marshal.SizeOf(typeof(OSVERSIONINFOEXW))
};
var dwlConditionMask = VerSetConditionMask(
VerSetConditionMask(
VerSetConditionMask(
0, VER_MAJORVERSION, VER_GREATER_EQUAL),
VER_MINORVERSION, VER_GREATER_EQUAL),
VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
osvi.dwMajorVersion = wMajorVersion;
osvi.dwMinorVersion = wMinorVersion;
osvi.wServicePackMajor = wServicePackMajor;
return VerifyVersionInfoW(ref osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, dwlConditionMask) != FALSE;
}
public static bool
IsWindowsXPOrGreater()
{
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 0);
}
public static bool
IsWindowsXPSP1OrGreater()
{
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 1);
}
public static bool
IsWindowsXPSP2OrGreater()
{
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 2);
}
public static bool
IsWindowsXPSP3OrGreater()
{
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 3);
}
public static bool
IsWindowsVistaOrGreater()
{
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 0);
}
public static bool
IsWindowsVistaSP1OrGreater()
{
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 1);
}
public static bool
IsWindowsVistaSP2OrGreater()
{
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 2);
}
public static bool
IsWindows7OrGreater()
{
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN7), LOBYTE(_WIN32_WINNT_WIN7), 0);
}
public static bool
IsWindows7SP1OrGreater()
{
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN7), LOBYTE(_WIN32_WINNT_WIN7), 1);
}
public static bool
IsWindows8OrGreater()
{
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN8), LOBYTE(_WIN32_WINNT_WIN8), 0);
}
public static bool
IsWindows8Point1OrGreater()
{
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINBLUE), LOBYTE(_WIN32_WINNT_WINBLUE), 0);
}
public static bool
IsWindowsThresholdOrGreater()
{
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINTHRESHOLD), LOBYTE(_WIN32_WINNT_WINTHRESHOLD), 0);
}
public static bool
IsWindows10OrGreater()
{
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINTHRESHOLD), LOBYTE(_WIN32_WINNT_WINTHRESHOLD), 0);
}
public static bool
IsWindowsServer()
{
var osvi = new OSVERSIONINFOEXW
{
dwOSVersionInfoSize = Marshal.SizeOf(typeof(OSVERSIONINFOEXW)),
wProductType = VER_NT_WORKSTATION
};
var dwlConditionMask = VerSetConditionMask(0, VER_PRODUCT_TYPE, VER_EQUAL);
return !VerifyVersionInfoW( ref osvi, VER_PRODUCT_TYPE, dwlConditionMask);
}
}
}
Unfortunately, it's a little more complicated than that. The "functions" are actually macros defined in VersionHelpers.h.
If you think of it, that's the only way to do it - they can't add functions to older Windows versions retroactively.
You have to port the macros over to C#.
VersionHelpers functions are not exported in any dll, but rather defined in VersionHelpers.h file,
in order to utilize the functionality in your C# code you can copy the functionality from the header file,
Import those 2 functions:
[DllImport("kernel32.dll")]
static extern ulong VerSetConditionMask(ulong dwlConditionMask, uint dwTypeBitMask, byte dwConditionMask);
[DllImport("kernel32.dll")]
static extern bool VerifyVersionInfo([In] ref OsVersionInfoEx lpVersionInfo, uint dwTypeMask, ulong dwlConditionMask);
Define the following structure:
[StructLayout(LayoutKind.Sequential)]
struct OsVersionInfoEx
{
public uint OSVersionInfoSize;
public uint MajorVersion;
public uint MinorVersion;
public uint BuildNumber;
public uint PlatformId;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string CSDVersion;
public ushort ServicePackMajor;
public ushort ServicePackMinor;
public ushort SuiteMask;
public byte ProductType;
public byte Reserved;
}
Then use the following function:
static bool IsWindowsVersionOrGreater(uint majorVersion, uint minorVersion, ushort servicePackMajor)
{
OsVersionInfoEx osvi = new OsVersionInfoEx();
osvi.OSVersionInfoSize = (uint)Marshal.SizeOf(osvi);
osvi.MajorVersion = majorVersion;
osvi.MinorVersion = minorVersion;
osvi.ServicePackMajor = servicePackMajor;
// These constants initialized with corresponding definitions in
// winnt.h (part of Windows SDK)
const uint VER_MINORVERSION = 0x0000001;
const uint VER_MAJORVERSION = 0x0000002;
const uint VER_SERVICEPACKMAJOR = 0x0000020;
const byte VER_GREATER_EQUAL = 3;
ulong versionOrGreaterMask = VerSetConditionMask(
VerSetConditionMask(
VerSetConditionMask(
0, VER_MAJORVERSION, VER_GREATER_EQUAL),
VER_MINORVERSION, VER_GREATER_EQUAL),
VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
uint versionOrGreaterTypeMask = VER_MAJORVERSION |VER_MINORVERSION | VER_SERVICEPACKMAJOR;
return VerifyVersionInfo(ref osvi, versionOrGreaterTypeMask, versionOrGreaterMask);
}
There's no need to work with interop/unmanaged code or add a target manifest.
Get Windows OS version with WMI
Like already mentioned here and on GetVersionEx and Environment.OSVersion docs, GetVersionEx behavior/availability changed with Windows 8.1. (And for .NET < 5.0, Environment.OSVersion reflects this)
The same applies to the VerifyVersionInfo function. If you use .NET 5 or Core, you can just use Environment.OSVersion again and by the way, my colleague working on our Core project, excluded the code that was querying WMI using ManagementObjectSearcher with directives as it did not compile for Core )
An alternate way would be to use the PInvoke from other answers with the Windows SDK counterparts (from ntdll.dll) of these functions
RtlGetVersion ( can use either the OSVERSIONINFOW a OSVERSIONINFOEXW structure, which are aliases for non-SDK counterparts. Just be sure to set the dwOSVersionInfoSize before calling it so it knows which one you are referencing. )
RtlVerifyVersionInfo
They use the same structs as the functions from kernel23.dll, and can be used the same way (also using the VerSetConditionMask function as substitute for the documented VER_SET_CONDITION macro but only Unicode versions are available, so be sure to annotate the structs with StructLayoutAttribute with Charset set to CharSet.Unicode as C# defaults to ANSI)
So code already posted should give reliable results if the following imports are used instead:
(In case you can't or don't want to use WMI or the registry)
[DllImport("kernel32.dll")]
private static extern ulong VerSetConditionMask(ulong dwlConditionMask, uint dwTypeBitMask, byte dwConditionMask);
[DllImport("ntdll.dll")]
private static extern uint RtlGetVersion(ref OSVERSIONINFOW lpVersionInformation);
[DllImport("ntdll.dll")]
private static extern uint RtlGetVersion(ref OSVERSIONINFOEXW lpVersionInformation);
[DllImport("ntdll.dll")]
private static extern bool RtlVerifyVersionInfo([In] ref OSVERSIONINFOEXW lpVersionInformation, uint dwTypeMask, ulong dwlConditionMask);

SetupDiEnumDriverInfo always return with Error 259 (No more Data available)

I am trying to access information about drivers associated with devices in C# utilizing the win32 APIs.
I have managed to enable/disable devices (so the handles I am retrieving seem OK), however I have no luck when trying to call SetupDiEnumDriverInfo.
This is the code I am using:
private List<String> ListCompatibleDrivers(IntPtr hDevInfo, SP_DEVINFO_DATA devInfoData)
{
List<String> result = new List<String>();
try
{
SP_DRVINFO_DATA drvInfo = new SP_DRVINFO_DATA();
for (int i = 0; SetupDiEnumDriverInfo(hDevInfo, devInfoData, SPDIT_CLASSDRIVER, i, drvInfo); i++)
{
result.Add(drvInfo.Description);
}
if (result.Count < 1)
{
result.Add(Marshal.GetLastWin32Error().ToString());
}
return result;
}
catch
{
throw;
}
}
Where the parameters can be assumed to be okay (as I said, other methods from the setup API use them successfully).
These are the struct and the DllImport which might be corrupt:
[StructLayout(LayoutKind.Sequential)]
public class SP_DRVINFO_DATA
{
public Int32 cbSize;
public Int32 driverType;
public UIntPtr reserved;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)]
public String description;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)]
public String mfgName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)]
public String providerName;
public FILETIME driverDate;
public Int64 driverVersion;
};
[DllImport("setupapi.dll", SetLastError = true)]
public static extern bool SetupDiEnumDriverInfo(IntPtr lpInfoSet, SP_DEVINFO_DATA deviceInfoData, UInt32 driverType, Int32 memberIndex, SP_DRVINFO_DATA driverInfoData);
The API call returns with false immediately, the Marshal.GetLastWin32Error().ToString() returns 259, which is ERROR_NO_MORE_ITEMS.
I just don't get it, and my hopes are high I am just making some stupid mistake that I am not able to see because I have read hardly anything but msdn lately, and it gets incredibly tiring...
Any help is greatly appreciated, thanks a lot!
Well off the top I can tell you you don't match the function signature which should be:
[DllImport("setupapi.dll", SetLastError = true, charset=Charset.Unicode)]
[return:MarshalAs(UnmanagedType.Bool)]
private static extern bool SetupDiEnumDriverInfo(
[In] IntPtr lpInfoSet,
[In, Optional] SP_DEVINFO_DATA deviceInfoData,
[In] UInt32 driverType,
[In] Int32 memberIndex,
[Out] out SP_DRVINFO_DATA driverInfoData);
That out is important as it specifies that it needs to pull back out the data from the PInvoke.
There are several problems with the struct, the most annoying being that one has to specify pack=4 so the native code will find the correct entry points.
This works:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 4)]
public struct SP_DRVINFO_DATA
{
public int cbSize;
public int DriverType;
public UInt32 Reserved;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string Description;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string MfgName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string ProviderName;
public System.Runtime.InteropServices.ComTypes.FILETIME DriverDate;
public long DriverVersion;
}
Of course it is a god idea to actually prefix the P/Invokes with Charset=Charset.Unicode, too.
Here are the API and struct definitions that both worked on x64 and x86. I am adding also SetupDiGetDriverInfoDetail, good chance that you'll also need it.
API:
DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool SetupDiGetDriverInfoDetail(
IntPtr DeviceInfoSet,
ref SP_DEVINFO_DATA DeviceInfoData,
ref SP_DRVINFO_DATA DriverInfoData,
ref SP_DRVINFO_DETAIL_DATA DriverInfoDetailData,
Int32 DriverInfoDetailDataSize,
ref Int32 RequiredSize);
[DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool SetupDiEnumDriverInfo(
IntPtr DeviceInfoSet,
ref SP_DEVINFO_DATA DeviceInfoData,
int DriverType,
int MemberIndex,
ref SP_DRVINFO_DATA DriverInfoData);
structs:
#if !WIN64
[StructLayout(LayoutKind.Sequential, Pack = 2, CharSet = CharSet.Unicode)]
#else
[StructLayout(LayoutKind.Sequential, Pack = 8, CharSet = CharSet.Unicode)]
#endif
public struct SP_DRVINFO_DATA
{
public int cbSize;
public uint DriverType;
public UIntPtr Reserved;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string Description;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string MfgName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string ProviderName;
public System.Runtime.InteropServices.ComTypes.FILETIME DriverDate;
public ulong DriverVersion;
}
#if !WIN64
[StructLayout(LayoutKind.Sequential, Pack = 2, CharSet = CharSet.Unicode)]
#else
[StructLayout(LayoutKind.Sequential, Pack = 8, CharSet = CharSet.Unicode)]
#endif
public struct SP_DRVINFO_DETAIL_DATA
{
public Int32 cbSize;
public System.Runtime.InteropServices.ComTypes.FILETIME InfDate;
public Int32 CompatIDsOffset;
public Int32 CompatIDsLength;
public IntPtr Reserved;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public String SectionName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public String InfFileName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public String DrvDescription;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1)]
public String HardwareID;
};

Mount other users hive with C# .net

I'm writing an application that will write some registry key for every selected user.
I was wondering if there was a proper way to mount another user's hive to write in it.
At the moment, I'm using "REG LOAD" to mount every hive. It's functional, but messy.
Any Idea ?
Thanks in advance for your answers.
Cheers.
--- EDIT 19.06.2013 ---
Okay, thanks for the help, I was able to call the function, but was unauthorized to mount the registry.
I tought it was a missing privilege, and force it to run in admin.
I still recieve a 0x522 error, which mean, according to MSDN, that I don't have the right to mount the hive.
I searched the web and found different explanation and possibilities, but I still can't manage to mount the hive.
I'm pretty new in C# developpement and Windows API...
Here's the code I tried to understand and used in my tests.
Am I missing something ?
Thanks in advance for your answer.
namespace mountregistry2
{
public partial class Form1 : Form
{
[StructLayout(LayoutKind.Sequential)]
public struct LUID
{
public int LowPart;
public int HighPart;
}
[StructLayout(LayoutKind.Sequential)]
public struct TOKEN_PRIVILEGES
{
public LUID Luid;
public int Attributes;
public int PrivilegeCount;
}
[DllImport("advapi32.dll", CharSet = CharSet.Auto)]
public static extern int OpenProcessToken(int ProcessHandle, int DesiredAccess,
ref int tokenhandle);
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern int GetCurrentProcess();
[DllImport("advapi32.dll", CharSet = CharSet.Auto)]
public static extern int LookupPrivilegeValue(string lpsystemname, string lpname,
[MarshalAs(UnmanagedType.Struct)] ref LUID lpLuid);
[DllImport("advapi32.dll", CharSet = CharSet.Auto)]
public static extern int AdjustTokenPrivileges(int tokenhandle, int disableprivs,
[MarshalAs(UnmanagedType.Struct)]ref TOKEN_PRIVILEGES Newstate, int bufferlength,
int PreivousState, int Returnlength);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int RegLoadKey(uint hKey, string lpSubKey, string lpFile);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int RegUnLoadKey(uint hKey, string lpSubKey);
public const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
public const int TOKEN_QUERY = 0x00000008;
public const int SE_PRIVILEGE_ENABLED = 0x00000002;
public const string SE_RESTORE_NAME = "SeRestorePrivilege";
public const string SE_BACKUP_NAME = "SeBackupPrivilege";
public const uint HKEY_USERS = 0x80000003;
public string shortname;
bool unloaded = false;
private void testmountregistry()
{
int token = 0;
int retval = 0;
TOKEN_PRIVILEGES TokenPrivileges1 = new TOKEN_PRIVILEGES();
TOKEN_PRIVILEGES TokenPrivileges2 = new TOKEN_PRIVILEGES();
LUID RestoreLuid = new LUID();
LUID BackupLuid = new LUID();
retval = GetCurrentProcess();
MessageBox.Show(retval.ToString("X")); //returns FFFFFFFF, which should work
retval = OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref token);
MessageBox.Show(retval.ToString("X"));//RETURNS 1
retval = LookupPrivilegeValue(null, SE_RESTORE_NAME, ref RestoreLuid);
MessageBox.Show(retval.ToString("X"));//Returns 1
retval = LookupPrivilegeValue(null, SE_BACKUP_NAME, ref BackupLuid);
MessageBox.Show(retval.ToString("X"));//Returns 1
TokenPrivileges1.PrivilegeCount = 1;
TokenPrivileges1.Attributes = SE_PRIVILEGE_ENABLED;
TokenPrivileges1.Luid = RestoreLuid;
TokenPrivileges2.PrivilegeCount = 1;
TokenPrivileges2.Attributes = SE_PRIVILEGE_ENABLED;
TokenPrivileges2.Luid = BackupLuid;
retval = AdjustTokenPrivileges(token, 0, ref TokenPrivileges1, 1024, 0, 0);
MessageBox.Show(retval.ToString("X"));//Returns 1
retval = AdjustTokenPrivileges(token, 0, ref TokenPrivileges2, 1024, 0, 0);
MessageBox.Show(retval.ToString("X"));//Returns 1
uint hkey_users = 0x80000003;
int interror = RegLoadKey(hkey_users, "test", #"C:\Users\Public\NTUSER.DAT");
MessageBox.Show(interror.ToString("X"));//Return 0x522
return;
}
}
}
You can call the RegLoadKey API method using platform invoke.
[DllImport("advapi32.dll", SetLastError = true)]
static extern Int32 RegLoadKey(IntPtr hKey, string lpSubKey, string lpFile);

Categories

Resources