Collectives™ on Stack Overflow
Find centralized, trusted content and collaborate around the technologies you use most.
Learn more about Collectives
Teams
Q&A for work
Connect and share knowledge within a single location that is structured and easy to search.
Learn more about Teams
Ask Question
I am using Delphi to remotely read and write the registry of a remote machine. This works when my account on my machine has admin access to the remote machine.
However, I'd like to be able to specify a username / pwd when connecting to read the registry so I can connect with alternate credentials.
With the file-system I called the following (with the username and password) and was able to establish a connection to the remote system and perform filesystem related functions. However, this does not appear to work with the registry.
netResource : TNetResource;
begin
FillChar(netResource, SizeOf(netResource), 0);
netResource.dwScope := RESOURCE_GLOBALNET;
netResource.dwType := RESOURCETYPE_DISK;
netResource.dwDisplayType := RESOURCEDISPLAYTYPE_SHARE;
netResource.dwUsage := RESOURCEUSAGE_CONNECTABLE;
netResource.lpRemoteName := PChar('\\192.168.1.105\IPC$');
WNetAddConnection2(netResource, PChar(password), PChar(username), 0);
And here is the example of the function I'd like to be able to call, but specify the credentials with access to the remote machine:
procedure TForm1.SetWallpaperKey() ;
reg:TRegistry;
begin
reg:=TRegistry.Create;
with reg do begin
if RegistryConnect('192.168.1.105') then
if OpenKey('\Control Panel\desktop', False) then begin
//change wallpaper and tile it
reg.WriteString ('Wallpaper','c:\windows\CIRCLES.bmp') ;
reg.WriteString ('TileWallpaper','1') ;
//disable screen saver//('0'=disable, '1'=enable)
reg.WriteString('ScreenSaveActive','0') ;
finally
reg.Free;
–
Mick , i can't resist give you a WMI solution for you problem ;) , the wmi have a class called StdRegProv
which allow you to access the registry in local and remote machines. A key point is the namespace where the class is located, that depends of the version of windows installed in the remote machine. so for Windows Server 2003, Windows XP, Windows 2000, Windows NT 4.0, and Windows Me/98/95 the StdRegProv
class is available in the root\default
namespace and for others versions like windows Vista/7 the namespace is root\CIMV2
.
Now to configure the credentials to access the registry, you must set these values in the SWbemLocator.ConnectServer
method in this way :
FSWbemLocator.ConnectServer(Server, 'root\default', User, Pass);
Another impor point is which this class just exposes methods to access the registry not properties, so you cannot use a wmi query, instead you must execute wmi methods.
check the next samples to see how it works.
checking if you have permissions over a key
Windows,
SysUtils,
ActiveX,
ComObj;
// The CheckAccess method verifies that the user possesses the specified
// permissions. The method returns a uint32 which is 0 if successful or some other
// value if any other error occurred.
procedure Invoke_StdRegProv_CheckAccess;
const
Server = '192.168.52.128';
User = 'Administrator';
Pass = 'password';
FSWbemLocator : OLEVariant;
FWMIService : OLEVariant;
FWbemObjectSet : OLEVariant;
FInParams : OLEVariant;
FOutParams : OLEVariant;
begin
FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
//http://msdn.microsoft.com/en-us/library/aa393664%28v=vs.85%29.aspx
//StdRegProv is preinstalled in the WMI namespaces root\default and root\cimv2.
//Windows Server 2003, Windows XP, Windows 2000, Windows NT 4.0, and Windows Me/98/95: StdRegProv is available only in root\default namespace.
FWMIService := FSWbemLocator.ConnectServer(Server, 'root\default', User, Pass);
//For Windows Vista or Windows 7 you must use the root\CIMV2 namespace
//FWMIService := FSWbemLocator.ConnectServer(Server, 'root\CIMV2', User, Pass);
FWbemObjectSet:= FWMIService.Get('StdRegProv');
FInParams := FWbemObjectSet.Methods_.Item('CheckAccess').InParameters.SpawnInstance_();
FInParams.hDefKey:=HKEY_LOCAL_MACHINE;
FInParams.sSubKeyName:='SYSTEM\CurrentControlSet';
FInParams.uRequired:=KEY_QUERY_VALUE;
FOutParams := FWMIService.ExecMethod('StdRegProv', 'CheckAccess', FInParams);
Writeln(Format('bGranted %s',[FOutParams.bGranted]));
Writeln(Format('ReturnValue %s',[FOutParams.ReturnValue]));
reading a string value
// The GetStringValue method returns the data value for a named value whose data
// type is REG_SZ.
procedure Invoke_StdRegProv_GetStringValue;
const
Server = '192.168.52.128';
User = 'Administrator';
Pass = 'password';
FSWbemLocator : OLEVariant;
FWMIService : OLEVariant;
FWbemObjectSet : OLEVariant;
FInParams : OLEVariant;
FOutParams : OLEVariant;
begin
FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
//http://msdn.microsoft.com/en-us/library/aa393664%28v=vs.85%29.aspx
//StdRegProv is preinstalled in the WMI namespaces root\default and root\cimv2.
//Windows Server 2003, Windows XP, Windows 2000, Windows NT 4.0, and Windows Me/98/95: StdRegProv is available only in root\default namespace.
FWMIService := FSWbemLocator.ConnectServer(Server, 'root\default', User, Pass);
//For Windows Vista or Windows 7 you must use the root\CIMV2 namespace
//FWMIService := FSWbemLocator.ConnectServer(Server, 'root\CIMV2', User, Pass);
FWbemObjectSet:= FWMIService.Get('StdRegProv');
FInParams := FWbemObjectSet.Methods_.Item('GetStringValue').InParameters.SpawnInstance_();
FInParams.hDefKey:=HKEY_LOCAL_MACHINE;
FInParams.sSubKeyName:='SOFTWARE\Borland\Delphi\5.0';
FInParams.sValueName:='App';
FOutParams := FWMIService.ExecMethod('StdRegProv', 'GetStringValue', FInParams);
Writeln(Format('sValue %s',[FOutParams.sValue]));
Writeln(Format('ReturnValue %s',[FOutParams.ReturnValue]));
writing a string value
// The SetStringValue method sets the data value for a named value whose data type
// is REG_SZ.
procedure Invoke_StdRegProv_SetStringValue;
const
Server = '192.168.52.128';
User = 'Administrator';
Pass = 'password';
FSWbemLocator : OLEVariant;
FWMIService : OLEVariant;
FWbemObjectSet : OLEVariant;
FInParams : OLEVariant;
FOutParams : OLEVariant;
begin
FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
FWMIService := FSWbemLocator.ConnectServer(Server, 'root\default', User, Pass);
FWbemObjectSet:= FWMIService.Get('StdRegProv');
FInParams := FWbemObjectSet.Methods_.Item('SetStringValue').InParameters.SpawnInstance_();
FInParams.hDefKey:=HKEY_LOCAL_MACHINE;
FInParams.sSubKeyName:='SOFTWARE\Borland\Delphi\5.0';
FInParams.sValueName:='Dummy';
FInParams.sValue:='ADummyValue';
FOutParams := FWMIService.ExecMethod('StdRegProv', 'SetStringValue', FInParams);
Writeln(Format('ReturnValue %s',[FOutParams.ReturnValue]));
For more options you must check the documentation about this class.
I hope this help you.
–
–
Now using the windows API , the TRegistry.RegistryConnect
function internally call the RegConnectRegistry
windows function , the documentation says :
If the current user does not have
proper access to the remote computer,
the call to RegConnectRegistry fails.
To connect to a remote registry, call
LogonUser with
LOGON32_LOGON_NEW_CREDENTIALS and
ImpersonateLoggedOnUser before calling
RegConnectRegistry.
Windows 2000: One possible workaround is to establish a session
to an administrative share such as
IPC$ using a different set of
credentials. To specify credentials
other than those of the current user,
use the WNetAddConnection2 function to
connect to the share. When you have
finished accessing the registry,
cancel the connection.
Windows XP Home Edition: You cannot use this function to connect to
a remote computer running Windows XP
Home Edition. This function does work
with the name of the local computer
even if it is running Windows XP Home
Edition because this bypasses the
authentication layer.
check the next samples
using the windows api registry functions
Windows,
Registry,
SysUtils;
procedure AccessRemoteRegistry(const lpMachineName, lpszUsername , lpszPassword: PChar);
const
LOGON32_LOGON_NEW_CREDENTIALS = 9;
REG_OPTION_OPEN_LINK = $00000008;
netResource : TNetResource;
dwFlags : DWORD;
dwRetVal : DWORD;
phToken : THandle;
phkResult : HKEY;
phkResult2 : HKEY;
lpType : DWORD;
lpData : PByte;
lpcbData : DWORD;
begin
ZeroMemory(@netResource, SizeOf(netResource));
netResource.dwType := RESOURCETYPE_ANY;
netResource.lpLocalName := nil;
netResource.lpRemoteName:= lpMachineName;
netResource.lpProvider := nil;
dwFlags := CONNECT_UPDATE_PROFILE;
dwRetVal := WNetAddConnection2(netResource, lpszPassword, lpszUsername, dwFlags);
if dwRetVal=NO_ERROR then
begin
Writeln('Connected');
if LogonUser(lpszUsername, nil, lpszPassword, LOGON32_LOGON_NEW_CREDENTIALS, LOGON32_PROVIDER_WINNT50,phToken) then
begin
if ImpersonateLoggedOnUser(phToken) then
begin
dwRetVal:=RegConnectRegistry(lpMachineName,HKEY_LOCAL_MACHINE,phkResult);
if dwRetVal = ERROR_SUCCESS then
begin
dwRetVal:=RegOpenKeyEx(phkResult,PChar('SOFTWARE\Borland\Delphi\5.0'), REG_OPTION_OPEN_LINK, KEY_QUERY_VALUE, phkResult2);
if dwRetVal = ERROR_SUCCESS then
begin
lpType:=REG_SZ;
//get the size of the buffer
dwRetVal:=RegQueryValueEx(phkResult2, PChar('App'), nil, @lpType, nil, @lpcbData);
if dwRetVal = ERROR_SUCCESS then
begin
GetMem(lpData,lpcbData);
dwRetVal:=RegQueryValueEx(phkResult2, 'App', nil, @lpType, lpData, @lpcbData);
if dwRetVal = ERROR_SUCCESS then
WriteLn(PChar(lpData))
Writeln(Format('RegQueryValueEx error %d',[dwRetVal]));
finally
FreeMem(lpData);
Writeln(Format('RegQueryValueEx error %d',[dwRetVal]));
finally
RegCloseKey(phkResult2);
Writeln(Format('RegOpenKeyEx error %d',[dwRetVal]));
Writeln(Format('RegConnectRegistry error %d',[dwRetVal]));
finally
RevertToSelf;
RaiseLastOSError;
finally
CloseHandle(phToken);
RaiseLastOSError;
finally
dwRetVal:=WNetCancelConnection2(netResource.lpRemoteName, CONNECT_UPDATE_PROFILE, false);
if dwRetVal<>NO_ERROR then
Writeln(Format('WNetCancelConnection2 error %d',[dwRetVal]));
Writeln(Format('WNetAddConnection2 Connection error %d',[dwRetVal]));
use in this way
AccessRemoteRegistry('\\192.168.52.128','NormalUser','password');
using the TRegistry delphi class
procedure AccessRemoteRegistry2(const lpMachineName, lpszUsername , lpszPassword: PChar);
const
LOGON32_LOGON_NEW_CREDENTIALS = 9;
REG_OPTION_OPEN_LINK = $00000008;
netResource : TNetResource;
dwFlags : DWORD;
dwRetVal : DWORD;
phToken : THandle;
Reg : TRegistry;
begin
ZeroMemory(@netResource, SizeOf(netResource));
netResource.dwType := RESOURCETYPE_ANY;
netResource.lpLocalName := nil;
netResource.lpRemoteName:= lpMachineName;
netResource.lpProvider := nil;
dwFlags := CONNECT_UPDATE_PROFILE;
dwRetVal := WNetAddConnection2(netResource, lpszPassword, lpszUsername, dwFlags);
if dwRetVal=NO_ERROR then
begin
Writeln('Connected');
if LogonUser(lpszUsername, nil, lpszPassword, LOGON32_LOGON_NEW_CREDENTIALS, LOGON32_PROVIDER_WINNT50,phToken) then
begin
if ImpersonateLoggedOnUser(phToken) then
begin
reg:=TRegistry.Create;
reg.RootKey:=HKEY_LOCAL_MACHINE;
if reg.RegistryConnect(lpMachineName) then
if reg.OpenKey('SOFTWARE\Borland\Delphi\5.0',False) then
WriteLn(reg.ReadString('App'));
finally
reg.CloseKey;
reg.Free;
finally
RevertToSelf;
RaiseLastOSError;
finally
CloseHandle(phToken);
RaiseLastOSError;
finally
dwRetVal:=WNetCancelConnection2(netResource.lpRemoteName, CONNECT_UPDATE_PROFILE, false);
if dwRetVal<>NO_ERROR then
Writeln(Format('WNetCancelConnection2 error %d',[dwRetVal]));
Writeln(Format('WNetAddConnection2 Connection error %d',[dwRetVal]));
use in this way
AccessRemoteRegistry2('\\192.168.52.128','NormalUser','password');
Maybe you need WNetAddConnection3? I don't think it enables remote registry though.
Personally though I would look into WMI, and network-named-pipes, which are methods of remote registry access that Windows supports out of the box.
Also, you know about TRegistry.RegistryConnect. It doesn't seem to have the userid/password, thing you want, but I am still not clear why that isn't enough.
–
–
In case anyone wants to use WNetAddConnection2 correctly in C#, here's some code. The problem is WNetAddConnection2 expects an IntPtr which holds the buffer of the NETRESOURCE, otherwise you get return code of 487 (0x1E7) which is ERROR_INVALID_ADDRESS. Attempt to access invalid address.
I personally was trying to get registry key that honored elevated privileges and thought by connecting to IPC$ it would work, but of course not, seems only way is using RegCreateKeyEx with the base key from RegConnectRegistry... which is acceptable as long as it actually works once I get around to it, haha!
public class IPCShareSession : IDisposable
#region PInvoke Functions,Structs,Enums
[DllImport("mpr.dll", CharSet = CharSet.Unicode)]
private static extern int WNetAddConnection2(IntPtr NetResource, string Password, string Username, WNetConnect Flags);
[DllImport("mpr.dll", CharSet = CharSet.Unicode)]
private static extern int WNetCancelConnection2(string ServerName, WNetDisconnect Flags, bool Force);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private class NETRESOURCE
public WNetResourceScope dwScope = 0;
public WNetResourceType dwType = 0;
public WNetResourceDisplayType dwDisplayType = 0;
public WNetResourceUsage dwUsage = 0;
public string lpLocalName = null;
public string lpRemoteName = null;
public string lpComment = null;
public string lpProvider = null;
private enum WNetResourceScope
Connected = 0x1,
GlobalNetwork = 0x2,
Remembered = 0x3,
Recent = 0x4,
Context = 0x5
public enum WNetResourceType
Any = 0,
Disk = 1,
Print = 2,
Reserved = 8
private enum WNetResourceUsage
Connectable = 0x1,
Container = 0x2,
NoLocalDevice = 0x4,
Sibling = 0x8,
Attached = 0x10,
All = Connectable | Container | Attached
private enum WNetResourceDisplayType
Generic = 0x0,
Domain = 0x1,
Server = 0x2,
Share = 0x3,
File = 0x4,
Group = 0x5,
Network = 0x6,
Root = 0x7,
ShareAdmin = 0x8,
Directory = 0x9,
Tree = 0xa,
NDSContainer = 0xb
private enum WNetConnect : int
CONNECT_UPDATE_PROFILE = 0x00000001,
CONNECT_UPDATE_RECENT = 0x00000002,
CONNECT_TEMPORARY = 0x00000004,
CONNECT_INTERACTIVE = 0x00000008,
CONNECT_PROMPT = 0x00000010,
CONNECT_REDIRECT = 0x00000080,
CONNECT_CURRENT_MEDIA = 0x00000200,
CONNECT_COMMANDLINE = 0x00000800,
CONNECT_CMD_SAVECRED = 0x00001000,
CONNECT_CRED_RESET = 0x00002000
private enum WNetDisconnect
DISCONNECT=0,
DISCONNECT_AND_REMOVE=1
#endregion
private string ServerShare = null;
private NETRESOURCE serverNR = null;
private bool bConnected = false;
public IPCShareSession(string ServerName, string ShareName = "IPC$")
ServerShare = string.Format(@"\\{0}\{1}", ServerName, ShareName);
//Setup nr to be a IPC share session
serverNR = new NETRESOURCE
dwType = WNetResourceType.Disk,
lpLocalName = null,
lpRemoteName = ServerShare,
lpProvider = null,
dwDisplayType = WNetResourceDisplayType.ShareAdmin,
dwUsage = WNetResourceUsage.Connectable,
public int Connect()
if(!bConnected)
IntPtr pNR = Marshal.AllocHGlobal(Marshal.SizeOf(serverNR));
Marshal.StructureToPtr(serverNR, pNR, false);
int ret = WNetAddConnection2(pNR, null, null, WNetConnect.CONNECT_TEMPORARY);
//Free our unmanaged pointer now that we're done with it.
Marshal.FreeHGlobal(pNR);
bConnected = ret == 0;
return ret;
return -1;
public int Disconnect()
int ret = 0;
if (bConnected)
ret = WNetCancelConnection2(ServerShare, WNetDisconnect.DISCONNECT, true);
bConnected = false;
ret = -1;
return ret;
#region IDisposable Support
private bool disposedValue = false; // To detect redundant calls
protected virtual void Dispose(bool disposing)
if (!disposedValue)
if (disposing)
if (bConnected)
Disconnect();
disposedValue = true;
public void Dispose()
Dispose(true);
#endregion
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.