delphi reg query doesnt output value [duplicate] - delphi

I'm trying to read HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run with OpenKeyReadOnly, and GetValueNames, but it's returning values from HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Run instead.
How can I read the 64-bit values instead of from a redirect to the 32-bit key?
The program was run as an administrative account. I also tried RegOpenKeyEx and RegEnumValue.
I'm using Delphi 2010.

you must use the KEY_WOW64_64KEY value when open the Registry with the TRegistry class.
from MSDN :
KEY_WOW64_64KEY Indicates that an
application on 64-bit Windows should
operate on the 64-bit registry view.
This flag is ignored by 32-bit
Windows.
This flag must be combined using the
OR operator with the other flags in
this table that either query or access
registry values.
try this sample app.
{$APPTYPE CONSOLE}
uses
Windows,
Classes,
registry,
SysUtils;
procedure ReadRegistry;
var
Registry: TRegistry;
List : TStrings;
begin
Registry := TRegistry.Create(KEY_WRITE OR KEY_WOW64_64KEY);
//Registry := TRegistry.Create(KEY_READ OR KEY_WOW64_64KEY);
List := TStringList.Create;
try
Registry.RootKey := HKEY_LOCAL_MACHINE;
if Registry.OpenKeyReadOnly('\SOFTWARE\Microsoft\Windows\CurrentVersion\Run') then
begin
Registry.GetValueNames(List);
Writeln(List.Text);
end;
Registry.CloseKey;
finally
Registry.Free;
List.Free;
end;
end;
begin
try
ReadRegistry();
except
on E:Exception do
Writeln(E.Classname, ': ', E.Message);
end;
Readln;
end.

Related

Different file hash of shortcut file when shortcut created from 32-bit or 64-bit program

I create a ShellLink Shortcut from a 64-bit program:
program ShellLinkShortcutHashTest;
{$APPTYPE CONSOLE}
{$R *.res}
uses
Winapi.Windows,
JclShell,
Winapi.ActiveX,
IdHashMessageDigest,
System.Classes, System.SysUtils;
const
ShortcutFile = 'R:\myshortcut.lnk';
ShortcutTarget = 'C:\Windows\System32\notepad.exe';
function GetHashFromFile(const AFileToHash: string): string;
var
IdMD5: TIdHashMessageDigest5;
FS: TFileStream;
begin
IdMD5 := TIdHashMessageDigest5.Create;
FS := TFileStream.Create(AFileToHash, fmOpenRead or fmShareDenyWrite);
try
Result := IdMD5.HashStreamAsHex(FS);
finally
FS.Free;
IdMD5.Free;
end;
end;
function SaveShortcutShellLink(const AFile: string): string;
var
SL: JclShell.TShellLink;
HR: Integer;
begin
Result := 'error';
SL.Target := ShortcutTarget;
SL.Description := 'My description';
HR := JclShell.ShellLinkCreate(SL, AFile);
if HR = Winapi.Windows.S_OK then
Result := 'OK - this is the shortcut file hash: ' + GetHashFromFile(AFile)
else
Result := 'Error: ' + IntToStr(HR);
end;
begin
try
Winapi.ActiveX.OleInitialize(nil);
try
Writeln(SaveShortcutShellLink(ShortcutFile));
finally
Winapi.ActiveX.OleUninitialize;
end;
Readln;
except
on E: Exception do
begin
Writeln(E.ClassName, ': ', E.Message);
Readln;
end;
end;
end.
The MD5 file hash from the shortcut file is: 4113F96CD9D6D94EB1B93D03B9604FFA.
I then build a 32-bit version of the SAME program. But the hash of the shortcut file created with the 32 bit program is different: 6512AB03F39307D9F7E3FC129140117A.
I have tested the MD5 hash of the shortcut file also with other external tools not related to Delphi. They also confirm the 64/32-bit difference.
Does this mean that shortcuts are binary-different if they have been created from a 64-bit program or from a 32-bit program? What is the difference? Could this be a security problem?
You're falling victim to the WOW64 filesystem redirector.
When your 64-bit application attempts to access :
C:\Windows\System32\notepad.exe
everything is normal you get a shortcut to the 64-bit notepad application in System32. When you attempt to access the same path from a 32-bit application, however, the redirector silently substitutes the WOW64 path in its place, to :
C:\Windows\SysWOW64\notepad.exe
and your application instead creates a shortcut to the 32-bit notepad application in SysWOW64. So these hash differently because they are shortcuts to two different programs.
The filesystem redirector is well documented and understood. While that doesn't preclude it having some security vulnerabilities, the redirector itself, and its documented behaviours, should not generally be considered a security risk.

How to employ DPROJ <ProjectGUID> within Delphi code?

I want to use a GUID to uniquely identify my Application and to get at this value from within the code. I see that there is a GUID that would be ideal in the DPROJ:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{D4DB842C-FB4C-481B-8952-77DA04E37102}</ProjectGuid>
Does this get into the exe anywhere, eg as a resource? If not, what is the neatest way of linking in this GUID value into my exe file and reading it in code. The above GUID resides in a dedicated text file and is pasted into the DPROJ with my DprojMaker tool, so I can INCLUDE it in anything you might suggest.
Thanks
AFAIK the <ProjectGUID> is not embedded in the Exe file, but you can create an application to read the project guid and insert as a resource in your exe.
Check this sample app which read a file a create/updates a resource in a exe.
program UpdateResEXE;
{$APPTYPE CONSOLE}
uses
Classes,
Windows,
SysUtils;
//you can improve this method to read the ProjectGUID value directly from the dproj file using XML.
procedure UpdateExeResource(Const Source, ResourceName, ExeFile:string);
var
LStream : TFileStream;
hUpdate : THANDLE;
lpData : Pointer;
cbData : DWORD;
begin
LStream := TFileStream.Create(Source,fmOpenRead or fmShareDenyNone);
try
LStream.Seek(0, soFromBeginning);
cbData:=LStream.Size;
if cbData>0 then
begin
GetMem(lpData,cbData);
try
LStream.Read(lpData^, cbData);
hUpdate:= BeginUpdateResource(PChar(ExeFile), False);
if hUpdate <> 0 then
if UpdateResource(hUpdate, RT_RCDATA, PChar(ResourceName),0,lpData,cbData) then
begin
if not EndUpdateResource(hUpdate,FALSE) then RaiseLastOSError
end
else
RaiseLastOSError
else
RaiseLastOSError;
finally
FreeMem(lpData);
end;
end;
finally
LStream.Free;
end;
end;
begin
try
if ParamCount<>3 then
begin
Writeln('Wrong parameters number');
Halt(1);
end;
Writeln(Format('Adding/Updating resource %s in %s',[ParamStr(2), ParamStr(3)]));
UpdateExeResource( ParamStr(1), ParamStr(2), ParamStr(3));
Writeln('Done');
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
Now from your app, you can use the Post build events to call this application on this way
"C:\The path where is the tool goes here\UpdateResEXE.exe" "C:\The path of the file which contains the ProjectGUID goes here\Foo.txt" Project_GUID "$(OUTPUTPATH)"
And use like so :
{$APPTYPE CONSOLE}
uses
Windows,
Classes,
System.SysUtils;
function GetProjectGUID : string;
var
RS: TResourceStream;
SS: TStringStream;
begin
RS := TResourceStream.Create(HInstance, 'Project_GUID', RT_RCDATA);
try
SS:=TStringStream.Create;
try
SS.CopyFrom(RS, RS.Size);
Result:= SS.DataString;
finally
SS.Free;
end;
finally
RS.Free;
end;
end;
begin
try
Writeln(Format('Project GUID %s',[GetProjectGUID]));
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
readln;
end.
Why not just hard-code your own GUID inside your code itself? The Code Editor has a CTRL+SHIFT+G keyboard shortcut for generating a new GUID string at the current active line of code. You can tweak that declaration into a constant variable for your code to use as needed, eg:
const
MyGuid: TGUID = '{04573E0E-DE08-4796-A5BB-E5F1F17D51F7}';

Connecting to a SQL Compact file (.sdf) using an ADO connection in Delphi

I'm attempting to use a local .sdf file as a means of temporary storage should the main database be unreachable. I have the .sdf file, but when I try to set it to the file it seems to not at all know if the .sdf exists. The current connection string I have currently is:
Driver={SQL Native Client};Data Source=C::\users\username\desktop\file\MyData.sdf;Persist Security Info=False
and for the Provider it generated for me:
Provider=Microsoft.SQLSERVER.CE.OLEDB.3.5
When I try to use the connection, I get a "Provider cannot be found. It may not be properly installed." The .sdf is most definitely in the folder. I also had/have a problem with it wanting a username and/or password, neither of which I had to specify when creating the database.
The Question: Is there something wrong with my connection string? Is it reasonable to use ADO connections to access SQL Compact Databases? Might there be an easier way to query/retrieve data from a temporary storage (I would prefer doing it with SQL though)?
Most documentation seems to be from 2003/2005, which is unhelpful.
I used "connectionstrings.com" for help making the string. Any advice would be helpful, thanks
First to open the sdf file you must use a provider compatible with the version of the sdf file. since you mention in your comments the version 3.5 you must use this provider Microsoft.SQLSERVER.CE.OLEDB.3.5
Then you must ensure which the provider is installed
Try this code to list the OLEDB providers installed in your system
{$APPTYPE CONSOLE}
{$R *.res}
uses
Windows,
Registry,
Classes,
SysUtils;
procedure ListOLEDBProviders;
var
LRegistry: TRegistry;
LIndex: Integer;
SubKeys,Values: TStrings;
CurKey, CurSubKey: string;
begin
LRegistry := TRegistry.Create;
try
LRegistry.RootKey := HKEY_CLASSES_ROOT;
if LRegistry.OpenKeyReadOnly('CLSID') then
begin
SubKeys := TStringList.Create;
try
LRegistry.GetKeyNames(SubKeys);
LRegistry.CloseKey;
for LIndex := 0 to SubKeys.Count - 1 do
begin
CurKey := 'CLSID\' + SubKeys[LIndex];
if LRegistry.KeyExists(CurKey) then
begin
if LRegistry.OpenKeyReadOnly(CurKey) then
begin
Values:=TStringList.Create;
try
LRegistry.GetValueNames(Values);
LRegistry.CloseKey;
for CurSubKey in Values do
if SameText(CurSubKey, 'OLEDB_SERVICES') then
if LRegistry.OpenKeyReadOnly(CurKey+'\ProgID') then
begin
Writeln(LRegistry.ReadString(''));
LRegistry.CloseKey;
if LRegistry.OpenKeyReadOnly(CurKey+'\OLE DB Provider') then
begin
Writeln(' '+LRegistry.ReadString(''));
LRegistry.CloseKey;
end;
end;
finally
Values.Free;
end;
end;
end;
end;
finally
SubKeys.Free;
end;
LRegistry.CloseKey;
end;
finally
LRegistry.Free;
end;
end;
begin
try
ListOLEDBProviders;
except
on E:Exception do
Writeln(E.Classname, ':', E.Message);
end;
Writeln('Press Enter to exit');
Readln;
end.
Now this is a basic sample to connect to a Sql Server compact file.
{$APPTYPE CONSOLE}
{$R *.res}
uses
ActiveX,
ComObj,
AdoDb,
SysUtils;
procedure Test;
Var
AdoQuery : TADOQuery;
begin
AdoQuery:=TADOQuery.Create(nil);
try
AdoQuery.ConnectionString:='Provider=Microsoft.SQLSERVER.CE.OLEDB.3.5;Data Source=C:\Datos\Northwind.sdf';
AdoQuery.SQL.Text:='Select * from Customers';
AdoQuery.Open;
While not AdoQuery.eof do
begin
Writeln(Format('%s %s',[AdoQuery.FieldByName('Customer ID').AsString,AdoQuery.FieldByName('Company Name').AsString]));
AdoQuery.Next;
end;
finally
AdoQuery.Free;
end;
end;
begin
try
CoInitialize(nil);
try
Test;
finally
CoUninitialize;
end;
except
on E:EOleException do
Writeln(Format('EOleException %s %x', [E.Message,E.ErrorCode]));
on E:Exception do
Writeln(E.Classname, ':', E.Message);
end;
Writeln('Press Enter to exit');
Readln;
end.
also check this wich helps with protected databases
"Provider=Microsoft.SQLSERVER.OLEDB.CE.2.0; data
source=\NorthWind.sdf; SSCE:Database Password="

How can a 32-bit program read the "real" 64-bit version of the registry?

I'm trying to read HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run with OpenKeyReadOnly, and GetValueNames, but it's returning values from HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Run instead.
How can I read the 64-bit values instead of from a redirect to the 32-bit key?
The program was run as an administrative account. I also tried RegOpenKeyEx and RegEnumValue.
I'm using Delphi 2010.
you must use the KEY_WOW64_64KEY value when open the Registry with the TRegistry class.
from MSDN :
KEY_WOW64_64KEY Indicates that an
application on 64-bit Windows should
operate on the 64-bit registry view.
This flag is ignored by 32-bit
Windows.
This flag must be combined using the
OR operator with the other flags in
this table that either query or access
registry values.
try this sample app.
{$APPTYPE CONSOLE}
uses
Windows,
Classes,
registry,
SysUtils;
procedure ReadRegistry;
var
Registry: TRegistry;
List : TStrings;
begin
Registry := TRegistry.Create(KEY_WRITE OR KEY_WOW64_64KEY);
//Registry := TRegistry.Create(KEY_READ OR KEY_WOW64_64KEY);
List := TStringList.Create;
try
Registry.RootKey := HKEY_LOCAL_MACHINE;
if Registry.OpenKeyReadOnly('\SOFTWARE\Microsoft\Windows\CurrentVersion\Run') then
begin
Registry.GetValueNames(List);
Writeln(List.Text);
end;
Registry.CloseKey;
finally
Registry.Free;
List.Free;
end;
end;
begin
try
ReadRegistry();
except
on E:Exception do
Writeln(E.Classname, ': ', E.Message);
end;
Readln;
end.

Getting connected USB info with Delphi on Vista

How can I get 'connected usb info'(device instance id, driver key name ..) from Registry in Vista or Windows 7 by using delphi?
Where is this information in Windows Registry?
I have a code it's working on XP but not in Vista.(c++ code: http://www.codeproject.com/KB/system/RemoveDriveByLetter.aspx)
Why the code is not working on Vista?
I'm really stack about that. Please help.
Thanks a lot for your answers.
You can use the WMI class Win32_DiskDrive. if you need get info about the logical drive you can query the wmi with something like this
Select * Win32_LogicalDisk where DriveType = 2
to access the WMI from delphi you must import the Microsoft WMIScripting V1.x Library using Component->Import Component->Import type library->Next->"Select the library"->Next->Add unit to project->Finish.
if you need more info about usb devices you can check also the next classes
Win32_USBControllerDevice
Win32_PnPEntity
See this example (tested in Delphi 2007 and Windows 7)
program GetWMI_USBConnectedInfo;
{$APPTYPE CONSOLE}
uses
Classes,
ActiveX,
Variants,
SysUtils,
WbemScripting_TLB in '..\..\..\Documents\RAD Studio\5.0\Imports\WbemScripting_TLB.pas';
procedure GetUSBDiskDriveInfo;
var
WMIServices : ISWbemServices;
Root : ISWbemObjectSet;
Item : Variant;
i : Integer;
StrDeviceUSBName: String;
begin
WMIServices := CoSWbemLocator.Create.ConnectServer('.', 'root\cimv2','', '', '', '', 0, nil);
Root := WMIServices.ExecQuery('Select * From Win32_DiskDrive Where InterfaceType="USB"','WQL', 0, nil);//more info in http://msdn.microsoft.com/en-us/library/aa394132%28VS.85%29.aspx
for i := 0 to Root.Count - 1 do
begin
Item := Root.ItemIndex(i);
Writeln('Caption '+VarToStr(Item.Caption));
Writeln('DeviceID '+VarToStr(Item.DeviceID));
Writeln('FirmwareRevision '+VarToStr(Item.FirmwareRevision));
Writeln('Manufacturer '+VarToStr(Item.Manufacturer));
Writeln('Model '+VarToStr(Item.Model));
Writeln('PNPDeviceID '+VarToStr(Item.PNPDeviceID));
Writeln('Status '+VarToStr(Item.Status));
End;
end;
begin
try
CoInitialize(nil);
GetUSBDiskDriveInfo;
Readln;
CoUninitialize;
except
on E:Exception do
Begin
CoUninitialize;
Writeln(E.Classname, ': ', E.Message);
Readln;
End;
end;
end.

Resources