I want to enumerate all dhcp reservation entries of our microsoft dhcp server with the microsoft dhcp server management api in c#.
This is my code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Net;
using System.Windows.Forms;
using System.Collections;
namespace Sequence
{
[StructLayout(LayoutKind.Sequential)]
public struct DHCP_CLIENT_INFO_ARRAY
{
public uint NumElements;
public IntPtr Clients;
}
[StructLayout(LayoutKind.Sequential)]
public struct DHCP_CLIENT_UID
{
public uint DataLength;
public IntPtr Data;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct DHCP_CLIENT_INFO
{
public uint ip;
public uint subnet;
public DHCP_CLIENT_UID mac;
[MarshalAs(UnmanagedType.LPWStr)]
public string ClientName;
[MarshalAs(UnmanagedType.LPWStr)]
public string ClientComment;
}
class CDHCP
{
public static ArrayList findDhcpClients(string server, string subnet)
{
ArrayList foundClients = new ArrayList();
uint parsedMask = StringIPAddressToUInt32(subnet);
uint resumeHandle = 0;
uint numClientsRead = 0;
uint totalClients = 0;
IntPtr info_array_ptr;
uint response = DhcpEnumSubnetClients(
server,
parsedMask,
ref resumeHandle,
65536,
out info_array_ptr,
ref numClientsRead,
ref totalClients
);
DHCP_CLIENT_INFO_ARRAY rawClients = (DHCP_CLIENT_INFO_ARRAY)Marshal.PtrToStructure(info_array_ptr, typeof(DHCP_CLIENT_INFO_ARRAY));
IntPtr current = rawClients.Clients;
for (int i = 0; i < (int)rawClients.NumElements; i++)
{
DHCP_CLIENT_INFO rawMachine = (DHCP_CLIENT_INFO)Marshal.PtrToStructure(Marshal.ReadIntPtr(current), typeof(DHCP_CLIENT_INFO));
CDHCPCLIENT thisClient = new CDHCPCLIENT();
thisClient.ip = UInt32IPAddressToString(rawMachine.ip);
thisClient.hostname = rawMachine.ClientName;
thisClient.mac = string.Format("{0:x2}-{1:x2}-{2:x2}-{3:x2}-{4:x2}-{5:x2}",
Marshal.ReadByte(rawMachine.mac.Data, 0),
Marshal.ReadByte(rawMachine.mac.Data, 1),
Marshal.ReadByte(rawMachine.mac.Data, 2),
Marshal.ReadByte(rawMachine.mac.Data, 3),
Marshal.ReadByte(rawMachine.mac.Data, 4),
Marshal.ReadByte(rawMachine.mac.Data, 5));
foundClients.Add(thisClient);
current = (IntPtr)((int)current + (int)Marshal.SizeOf(typeof(IntPtr)));
}
return foundClients;
}
public static uint StringIPAddressToUInt32(string ip)
{
IPAddress i = IPAddress.Parse(ip);
byte[] ipByteArray = i.GetAddressBytes();
uint ipUint = (uint)ipByteArray[0] << 24;
ipUint += (uint)ipByteArray[1] << 16;
ipUint += (uint)ipByteArray[2] << 8;
ipUint += (uint)ipByteArray[3];
return ipUint;
}
public static string UInt32IPAddressToString(uint ip)
{
IPAddress i = new IPAddress(ip);
string[] ipArray = i.ToString().Split('.');
return ipArray[3] + "." + ipArray[2] + "." + ipArray[1] + "." + ipArray[0];
}
[DllImport("C:\\Windows\\System32\\dhcpsapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern uint DhcpEnumSubnetClients(
string ServerIpAddress,
uint SubnetAddress,
ref uint ResumeHanle,
uint PreferredMaximum,
out IntPtr ClientInfo,
ref uint ElementsRead,
ref uint ElementsTotal);
}
}
Unfortunately I'm getting a NullReferenceException at this line:
DHCP_CLIENT_INFO_ARRAY rawClients = (DHCP_CLIENT_INFO_ARRAY)Marshal.PtrToStructure(info_array_ptr, typeof(DHCP_CLIENT_INFO_ARRAY));
I' calling the function like this:
public void GetDHCPReservation()
{
ArrayList clients = CDHCP.findDhcpClients("192.168.1.3", "192.168.1.5");
foreach (CDHCPCLIENT c in clients)
{
MessageBox.Show(string.Format("(0,-35}{1,-15}{2,-15}", c.hostname, c.ip, c.mac));
}
}
Can anybody help me?
Thanks in advance.
I think I've just solved my problem.
The reason why I was getting the NullReferenceException was because the IntPtr info_array_ptr always pointed to 0 (zero). That was because of not enough user rights on the dhcp server. After I added the user with which I'm running my application to the domain admins everything worked well.
Related
Attempting to retrieve a large list of open files from a file server returns the ERROR_MORE_DATA value (Error number 234), but works fine when dealing with only a small list of files (seems to return around 84 entries). This code is based upon the example at: http://pinvoke.net/default.aspx/netapi32/NetFileEnum.html
Most examples I have found don't really touch on how to handle a large number of files. From my understanding, this has something to do with the resume_handle, however I'm not sure what needs to be done. Do I need to somehow call this method in a loop?
Code is as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace OpenFiles
{
class Program
{
public static string computername = "computername";
static void Main(string[] args)
{
List<string> theFileList = NativeMethods.GetFiles(computername);
foreach (string file in theFileList)
{
Console.WriteLine(file);
}
}
}
static class NativeMethods
{
[DllImport("netapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
static extern int NetFileEnum(
string servername,
string basepath,
string username,
int level,
ref IntPtr bufptr,
int prefmaxlen,
out int entriesread,
out int totalentries,
IntPtr resume_handle
);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
struct FILE_INFO_3
{
public int fi3_id;
public int fi3_permission;
public int fi3_num_locks;
[MarshalAs(UnmanagedType.LPWStr)]
public string fi3_pathname;
[MarshalAs(UnmanagedType.LPWStr)]
public string fi3_username;
}
[DllImport("Netapi32.dll", SetLastError = true)]
static extern int NetApiBufferFree(IntPtr Buffer);
public static List<string> GetFiles(string Computername)
{
const int MAX_PREFERRED_LENGTH = -1;
int dwReadEntries;
int dwTotalEntries;
IntPtr pBuffer = IntPtr.Zero;
FILE_INFO_3 pCurrent = new FILE_INFO_3();
List<string> fileList = new List<string>();
int dwStatus = NetFileEnum(Computername, null, null, 3, ref pBuffer, MAX_PREFERRED_LENGTH, out dwReadEntries, out dwTotalEntries, IntPtr.Zero);
if (dwStatus == 0)
{
for (int dwIndex = 0; dwIndex < dwReadEntries; dwIndex++)
{
IntPtr iPtr = new IntPtr(pBuffer.ToInt32() + (dwIndex * Marshal.SizeOf(pCurrent)));
pCurrent = (FILE_INFO_3)Marshal.PtrToStructure(iPtr, typeof(FILE_INFO_3));
string fileInfo = pCurrent.fi3_id + "," +
pCurrent.fi3_num_locks + "," +
pCurrent.fi3_pathname + "," +
pCurrent.fi3_permission + "," +
pCurrent.fi3_username;
fileList.Add(fileInfo);
}
NetApiBufferFree(pBuffer);
}
else
{
Console.WriteLine("error: " + dwStatus);
}
return fileList;
}
}
}
In my limited experience a very large number of results can be larger than the max buffer. In this case a more data response is given and instructs us to call again with the provided resume handle. In your example, the resume handle will not be changed because the DllImport signature doesn't define it as an out parameter. Using the resume handle result from the first call (passing in zero means first call) allows you to receive the next batch. Loop until you receive a success response or some other error.
Be sure to fix the issue where the NetFileEnum signature is defined.
The resume handle is not defined with an out so cannot be changed by the called function.
Try the following DLL Import signature instead:
[DllImport("netapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
static extern int NetFileEnum(
string servername,
string basepath,
string username,
int level,
ref IntPtr bufptr,
int prefmaxlen,
out int entriesread,
out int totalentries,
out IntPtr resume_handle
);
You should be able to re-call NetFileEnum with the resulting resume handle multiple times when you get a more data response.
Im trying to build a small app that would send input to a game. After searching for a while, I found many answers that suggest SendInput should be used.
Below there is the code that I'm working on (basically doing a lots of tests to see what works, hence the messiness). I would suggest you ignore most of the code, the line that interests me , or should I say that causes the build problem is:
public static extern uint SendInput(
uint nInputs,[MarshalAs(UnmanagedType.LPArray), In] INPUT[] pInputs, int cbSize);
This gives me the error :
'INPUT' is inaccessible due to its protection level.
I am new to C# (and Windows programming), so I cannot really figure out what I should do to fix that.
Any help would be appreciated.
Thanks in advance.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
//using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using WindowsInput;
namespace WindowsFormsApplication1
{
[Flags]
public enum KeyFlag
{
KeyDown = 0x0000,
KeyUp = 0x0002,
Scancode = 0x0008
}
internal static class VirtualKeyboard
{
public static void KeyDown(System.Windows.Forms.Keys key)
{
Console.WriteLine("Sending keybdevent: " + (byte)key);
//keybd_event((byte)key, 0, 0, 0);
/*INPUT[] InputData = new INPUT[2];
Key ScanCode = Microsoft.DirectX.DirectInput.Key.W;
InputData[0].type = 1; //INPUT_KEYBOARD
InputData[0].wScan = (ushort)ScanCode;
InputData[0].dwFlags = (uint)SendInputFlags.KEYEVENTF_SCANCODE;
InputData[1].type = 1; //INPUT_KEYBOARD
InputData[1].wScan = (ushort)ScanCode;
InputData[1].dwFlags = (uint)(SendInputFlags.KEYEVENTF_KEYUP | SendInputFlags.KEYEVENTF_UNICODE);
// send keydown
if (SendInput(2, InputData, Marshal.SizeOf(InputData[1])) == 0)
{
System.Diagnostics.Debug.WriteLine("SendInput failed with code: " +
Marshal.GetLastWin32Error().ToString());
}*/
//InputSimulator.SimulateKeyDown(VirtualKeyCode.VK_E);
Console.WriteLine("Exit.....");
}
[DllImport("user32.dll", SetLastError = true)]
public static extern uint SendInput(uint nInputs, [MarshalAs(UnmanagedType.LPArray), In] INPUT[] pInputs, int cbSize);
public static void SendKey(short keyCode, KeyFlag keyFlag)
{
INPUT[] InputData = new INPUT[1];
InputData[0].type = 1;
InputData[0].ki.wScan = keyCode; // 0x14 = T for example
InputData[0].ki.dwFlags = (int)keyFlag;
InputData[0].ki.time = 0;
InputData[0].ki.dwExtraInfo = IntPtr.Zero;
SendInput(1, InputData, Marshal.SizeOf(typeof(INPUT)));
}
public static void PressKey(short key)
{
SendKey(key, KeyFlag.KeyDown | KeyFlag.Scancode);
SendKey(key, KeyFlag.KeyUp | KeyFlag.Scancode);
}
public static void KeyUp(System.Windows.Forms.Keys key)
{
//keybd_event((byte)key, 0, 0x7F, 0);
}
}
}
The INPUT struct must be a higher access level, such as public so other classes can access it. See access modifiers.
public struct INPUT
{
...
}
In C# you have to explicitly mark struct members as public. In c++ they are automatically public. So you must mark INPUT as public.
So, I'm programming in C#, and I am trying to get a item id from the SysListView32, then send a LVM_DELETEITEM message to remove the item from the list view.
My code:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using Microsoft.Win32.SafeHandles;
using System.Runtime.InteropServices;
using System.Text;
using System.ComponentModel;
using System.Windows.Forms;
namespace projone
{
class Hooker
{
[DllImport("user32.dll", EntryPoint = "FindWindowA")]
private static extern Int32 apiFindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", EntryPoint = "FindWindowExA")]
private static extern Int32 apiFindWindowEx(Int32 hWnd1, Int32 hWnd2, string lpsz1, string lpsz2);
[DllImport("user32.dll", EntryPoint = "SendMessageA")]
private static extern Int32 apiSendMessage(int hWnd, int wMsg, int wParam, int lParam);
[DllImport("user32.dll", EntryPoint = "GetDesktopWindow")]
private static extern Int32 apiGetDesktopWindow();
static Int32 LVM_FIRST = 4096;
static Int32 LVM_DELETEITEM = LVM_FIRST + 8;
static Int32 LVM_SORTITEMS = LVM_FIRST + 48;
static Int32 LVM_DELETECOLUMN = LVM_FIRST + 28;
static Int32 LVM_FINDITEM = LVM_FIRST + 13;
static Int32 LVM_GETITEMTEXT = LVM_FIRST + 45;
public static void withdrawProcess()
{
Int32 lhWndParent = apiFindWindow(null, "Windows Task Manager");
Int32 lhWndProcessList = 0;
Int32 lhWndDialog = 0;
for (int i = 1; (i < 7); i++)
{
lhWndDialog = apiFindWindowEx(lhWndParent, lhWndDialog, null, null);
if((lhWndProcessList == 0))
{
lhWndProcessList = apiFindWindowEx(lhWndDialog, 0, "SysListView32", "Processes");
}
}
// Create List
List<string> processes = new List<string>();
// Loops
int processItemCount = 0;
Process[] processlist = Process.GetProcesses();
foreach (Process theprocess in processlist)
{
processItemCount += 1;
processes.Add(theprocess.ProcessName.ToString());
if (theprocess.ProcessName.Equals("notepad"))
{
apiSendMessage(lhWndProcessList, LVM_SORTITEMS, 0, 0);
apiSendMessage(lhWndProcessList, LVM_DELETEITEM, theprocess.Id, 0);
}
}
Console.WriteLine(processItemCount);
//processes.ForEach(Console.WriteLine);
//apiSendMessage(lhWndProcessList, LVM_DELETEITEM, 0, "0"); // third entry is item id in listview
}
}
}
Any ideas on how to correct it so it'll successfully delete the item? No, this isn't for any sort of "virus", I'm trying to see if its possible to without directly hooking and intercepting the NtQuerySystemInformation.
The wparam argument of the SendMessage call when sending LVM_DELETEITEM must be the index of the item to delete; you are passing the process id instead.
The lparam argument of the SendMessage call when sending LVM_DELETEITEM must be zero; you are passing a pointer to a string.
I would not be surprised if Task Manager has protections to prevent you from doing what you are trying to do. I would be surprised if it didn't. Do not hide programs from Task Manager.
I'm trying to get gettext to work in a multithreaded server environment, where the server will localize strings based on the clients locale.
I'm basing my POC code on this example: http://www.mono-project.com/archived/internationalization. My implementation of the sample seems to be correct. Running my code on the command line like this:
LANGUAGE=da_DK mono Test.exe produces Mit navn er Enzo
Given the following code:
using System;
using Mono.Unix;
using Mono.Unix.Native;
using System.Runtime.InteropServices;
namespace Test
{
public class Locale : IDisposable
{
static class LocaleCategory
{
public const int LC_CTYPE = 0;
public const int LC_NUMERIC = 1;
public const int LC_TIME = 2;
public const int LC_COLLATE = 3;
public const int LC_MONETARY = 4;
public const int LC_MESSAGES = 5;
public const int LC_ALL = 6;
public const int LC_PAPER = 7;
public const int LC_NAME = 8;
public const int LC_ADDRESS = 9;
public const int LC_TELEPHONE = 10;
public const int LC_MEASUREMENT = 11;
public const int LC_IDENTIFICATION = 12;
}
[Flags]
enum LocaleMask
{
LC_CTYPE_MASK = (1 << LocaleCategory.LC_CTYPE),
LC_NUMERIC_MASK = (1 << LocaleCategory.LC_NUMERIC),
LC_TIME_MASK = (1 << LocaleCategory.LC_TIME),
LC_COLLATE_MASK = (1 << LocaleCategory.LC_COLLATE),
LC_MONETARY_MASK = (1 << LocaleCategory.LC_MONETARY),
LC_MESSAGES_MASK = (1 << LocaleCategory.LC_MESSAGES),
LC_PAPER_MASK = (1 << LocaleCategory.LC_PAPER),
LC_NAME_MASK = (1 << LocaleCategory.LC_NAME),
LC_ADDRESS_MASK = (1 << LocaleCategory.LC_ADDRESS),
LC_TELEPHONE_MASK = (1 << LocaleCategory.LC_TELEPHONE),
LC_MEASUREMENT_MASK = (1 << LocaleCategory.LC_MEASUREMENT),
LC_IDENTIFICATION_MASK = (1 << LocaleCategory.LC_IDENTIFICATION),
LC_ALL = LC_CTYPE_MASK|LC_NUMERIC_MASK|LC_TIME_MASK|LC_COLLATE_MASK|LC_MONETARY_MASK|LC_MESSAGES_MASK|
LC_PAPER_MASK|LC_NAME_MASK|LC_ADDRESS_MASK|LC_TELEPHONE_MASK|LC_MEASUREMENT_MASK|LC_IDENTIFICATION_MASK
}
[DllImport ("libc", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr newlocale (Int32 categoryMask, IntPtr locale, IntPtr baseLocale);
[DllImport ("libc", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr duplocale (IntPtr locale);
[DllImport ("libc", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr uselocale (IntPtr newLocale);
[DllImport ("libc", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr freelocale (IntPtr localObj);
IntPtr m_oldLocale;
IntPtr m_newLocale;
IntPtr LC_GLOBAL_LOCALE;
ApplicationException BuildException(string message)
{
Errno errno = Stdlib.GetLastError ();
return new ApplicationException(string.Format (message + ": {0}:{1}", errno, Stdlib.strerror (errno)));
}
public Locale(string localeName)
{
LC_GLOBAL_LOCALE = new IntPtr (-1);
IntPtr marshalledLocaleName = UnixMarshal.StringToHeap (localeName);
if (marshalledLocaleName == IntPtr.Zero)
throw BuildException("Error marshalling string");
try{
IntPtr duplicateGlobal = duplocale(LC_GLOBAL_LOCALE);
if(duplicateGlobal == IntPtr.Zero)
throw BuildException("Error duplicating global");
m_newLocale = newlocale ((Int32)LocaleMask.LC_MESSAGES_MASK, marshalledLocaleName, duplicateGlobal);
if(m_newLocale == IntPtr.Zero)
throw BuildException(string.Format("Error getting locale '{0}'", localeName));
m_oldLocale = uselocale (m_newLocale);
if(m_oldLocale == IntPtr.Zero)
throw BuildException("Error using locale");
}
finally {
UnixMarshal.FreeHeap (marshalledLocaleName);
}
}
~Locale()
{
Dispose(false);
}
public void Dispose()
{
Dispose (true);
GC.SuppressFinalize (this);
}
protected virtual void Dispose(bool disposing)
{
if (m_newLocale != IntPtr.Zero && m_oldLocale != IntPtr.Zero)
{
uselocale(m_oldLocale);
freelocale (m_newLocale);
m_newLocale = IntPtr.Zero;
m_oldLocale = IntPtr.Zero;
}
}
}
class MainClass
{
public static void Main (string[] args)
{
using (Locale l = new Locale ("da_DK")) {
Catalog.Init ("i18n", "./locale");
Console.WriteLine (Catalog.GetString ("My name is {0}"), "Enzo");
}
}
}
}
I would have expected:
mono Text.exe to produce the same output, but ... it doesn't, instead it produces: My name is Enzo. Clearly the code doesn't set the thread locale correctly, but I cannot see where my mistake is.
My question is: What am I doing wrong?
and as a follow up: Do I really need to add the locales prior to using them?
I.e. I had to add the danish local like this:
sudo locale-gen da_DK
sudo update-locale
PS: Eventually this code will integrate with Mono.Addins, which uses gettext, so I'm pretty much stuck with this technology.
I am trying to read data from the registry files of other machines. Basically I have the hard drives of other systems, from which I can copy out, or directly read, for example, the SYSTEM file (Windows/system32/config/SYSTEM), so I can read data from the USBStor keys (and other stuff).
Please note I'm NOT trying to read .REG files that are exported from the registry, and NOT trying to read the the hives from the local machine. ;-)
I have been trying to find any type of library or native .Net way to do this, preferably for free! There is lots of references to reading .REG files but not the "flat" files taken from other systems.
Anyone come across this before?
Check out RegLoadKey() (MSDN here), you should be able to do something like this:
using System.Runtime.InteropServices;
using Microsoft.Win32;
namespace ConsoleApplication1
{
class Program
{
[DllImport("advapi32.dll")]
public static extern int RegLoadKey(uint hKey, string lpSubKey, string lpFile);
[DllImport("advapi32.dll")]
public static extern int RegUnLoadKey(uint hKey, string lpSubKey);
[DllImport("advapi32.dll")]
public static extern int OpenProcessToken(int ProcessHandle, int DesiredAccess, ref int tokenhandle);
[DllImport("kernel32.dll")]
public static extern int GetCurrentProcess();
[DllImport("advapi32.dll")]
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")]
public static extern int LookupPrivilegeValue(string lpsystemname, string lpname, [MarshalAs(UnmanagedType.Struct)] ref LUID lpLuid);
[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;
}
static void Main(string[] args)
{
int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
int SE_PRIVILEGE_ENABLED = 0x00000002;
int TOKEN_QUERY = 0x00000008;
int token = 0;
int retval = 0;
uint HKU = 0x80000003;
string SE_BACKUP_NAME = "SeBackupPrivilege";
string SE_RESTORE_NAME = "SeRestorePrivilege";
string tmpHive = "offlineSystemHive";
string offlineHive = "E:\\Windows\\system32\\config\\SYSTEM";
LUID RestoreLuid = new LUID();
LUID BackupLuid = new LUID();
TOKEN_PRIVILEGES TP = new TOKEN_PRIVILEGES();
TOKEN_PRIVILEGES TP2 = new TOKEN_PRIVILEGES();
retval = OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref token);
retval = LookupPrivilegeValue(null, SE_RESTORE_NAME, ref RestoreLuid);
retval = LookupPrivilegeValue(null, SE_BACKUP_NAME, ref BackupLuid);
TP.PrivilegeCount = 1;
TP.Attributes = SE_PRIVILEGE_ENABLED;
TP.Luid = RestoreLuid;
TP2.PrivilegeCount = 1;
TP2.Attributes = SE_PRIVILEGE_ENABLED;
TP2.Luid = BackupLuid;
retval = AdjustTokenPrivileges(token, 0, ref TP, 1024, 0, 0);
retval = AdjustTokenPrivileges(token, 0, ref TP2, 1024, 0, 0);
int rtnVal = RegLoadKey(HKU, tmpHive, offlineHive);
Console.WriteLine(rtnVal); //should be 0
RegistryKey baseKey = Registry.Users.OpenSubKey("offlineSystemHive\\ControlSet001\\Control\\ComputerName\\ComputerName");
Console.WriteLine(baseKey.GetValue("ComputerName"));
baseKey.Close();
rtnVal = RegUnLoadKey(HKU, tmpHive);
Console.WriteLine(rtnVal); //should be 0
}
}
}
You need to use the RegistryKey.OpenRemoteBaseKey method explained here. Note that according to the linked msdn documentation:
In order for a key to be opened remotely, both the server and client
machines must be running the remote registry service, and have remote
administration enabled.
To enable the remote registry service, use the link Blorgbeard mentioned in the comment: http://technet.microsoft.com/en-us/library/cc754820.aspx
Here is a sample:
RegistryKey FetchedRemoteMachineKey;
FetchedRemoteMachineKey = RegistryKey.OpenRemoteBaseKey(
RegistryHive.CurrentUser, RemoteMachineName).OpenSubKey(
"Machine");