How do you create your own moniker (URL Protocol) on Windows systems? - windows

How do you create your own custom moniker (or URL Protocol) on Windows systems?
Examples:
http:
mailto:
service:

Take a look at Creating and Using URL Monikers , About Asynchronous Pluggable Protocols and Registering an Application to a URL Protocol from MSDN

Here's some old Delphi code we used as a way to get shortcuts in a web application to start a windows program locally for the user.
procedure InstallIntoRegistry;
var
Reg: TRegistry;
begin
Reg := TRegistry.Create;
try
Reg.RootKey := HKEY_CLASSES_ROOT;
if Reg.OpenKey('moniker', True) then
begin
Reg.WriteString('', 'URL:Name of moniker');
Reg.WriteString('URL Protocol', '');
Reg.WriteString('Source Filter', '{E436EBB6-524F-11CE-9F53-0020AF0BA770}');
Reg.WriteInteger('EditFlags', 2);
if Reg.OpenKey('shell\open\command', True) then
begin
Reg.WriteString('', '"' + ParamStr(0) + '" "%1"');
end;
end else begin
MessageBox(0, 'You do not have the necessary access rights to complete this installation!' + Chr(13) +
'Please make sure you are logged in with a user account with administrative rights!', 'Access denied', 0);
Exit;
end;
finally
FreeAndNil(Reg);
end;
MessageBox(0, 'Application WebStart has been installed successfully!', 'Installed', 0);
end;

Inside OLE from Craig Brockschmidt probably has the best coverage on monikers. If you want to dig a little deeper into this topic, I'd recommend getting this book. It is also contained on the MSDN disk that came along with VS 6.0, in case you still have that.

Related

Inno Setup detect Windows Firewall state

I need to detect the Windows Firewall state (i.e. whether it is enabled or not) in order to display a message warning that a Firewall rule may need to be configured to allow inbound connections on specific ports when the Firewall is enabled, but not when it isn't. See below code example:
[Code]
//Check if Windows Firewall is enabled
function IsWindowsFirewallEnabled(): Boolean;
begin
//Method required here
Result := True;
end;
function NextButtonClick(CurPageID: Integer): Boolean;
begin
//Display a warning message on a Server install if Windows Firewall is enabled
if CurPageID = wpSelectComponents and IsComponentSelected('Server') and IsWindowsFirewallEnabled then
begin
MsgBox('Windows Firewall is currently enabled.' + #13#10 + #13#10 +
'You may need to enable inbound connections on ports 2638, 445 and 7.'
mbInformation, MB_OK);
Result := True;
end;
end;
What I need is a method for the IsWindowsFirewallEnabled function. One way I have read about, and ironically has now more or less been suggested below whilst I was in the middle of updating the question with this information anyway, would appear to be reading the EnableFirewall value from the Registry:
//Check if Windows Firewall is enabled
function IsWindowsFirewallEnabled(): Boolean;
var
crdFirewallState: Cardinal;
begin
RegQueryDwordValue(HKLM, 'SYSTEM\CurrentControlSet\Services\SharedAccess\Parameters\FirewallPolicy\StandardProfile',
'EnableFirewall', crdFirewallState);
if crdFirewallState = 1 then
Result := True;
end;
However, I am not convinced by this method as the Registry values for all the profiles show enabled on my work PC, but looking in Control Panel the Domain profile shows disabled (I assume this is related to a Group Policy).
Note, that this needs to work for both Windows XP and Server 2003, and for Windows Vista and Server 2008 and above.
Therefore, what's the most reliable or recommended way to do this?
You would need to determine the registry entry and then query it in a manner similar to this using Innosetup's registry query ability.
var
Country: String;
begin
if RegQueryStringValue(HKEY_CURRENT_USER, 'Control Panel\International',
'sCountry', Country) then
begin
// Successfully read the value
MsgBox('Your country: ' + Country, mbInformation, MB_OK);
end;
end;
http://www.jrsoftware.org/ishelp/index.php?topic=isxfunc_regquerystringvalue
Allegedly this is the information for the registry key:
Path: HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\WindowsFirewall\DomainProfile
Location: Local Machine
Value Name: EnableFirewall
Data Type: DWORD (DWORD Value)
Enabled Value: 0
Disabled Value: 1

TNetSharingManager and Windows 8 & 10: Access Denied

I have a delphi porgram that uses TNetsharingmanager tool to enable and disable communication through NIC card. It has worked flawlessly on Windows XP and 7, but it won't on Windows 8 and 10. It keeps raising "Access Denied" error, when my program tries to connect to the first available NIC card on start up. I can't seem to figure this out. I thought maybe its because of the current user doesn't have the permission to make connection, but that isn't the case. I even ran my program as an administrator and still raises the error. Once you okay the error box, my program continues without a problem.
Here is the code I use:
procedure TDXCommdlg.GetConnectionList(Strings,IdList: TStrings);
var
pEnum: IEnumVariant;
vNetCon: OleVARIANT;
dwRetrieved: Cardinal;
pUser: NETCONLib_TLB.PUserType1;
NetCon : INetConnection;
begin
Strings.Clear;
IdList.Clear;
pEnum := (NetSharingManager1.EnumEveryConnection._NewEnum as IEnumVariant);
while (pEnum.Next(1, vNetCon, dwRetrieved) = S_OK) do
begin
(IUnknown(vNetCon) as INetConnection).GetProperties(pUser);
NetCon := (IUnknown(vNetCon) as INetConnection);
if (pUser.Status in [NCS_CONNECTED,NCS_CONNECTING])
and (pUser.MediaType in [NCM_LAN,NCM_SHAREDACCESSHOST_LAN,NCM_ISDN] )
and (GetMacAddress(GuidToString(pUser.guidId))<>'' ) then
begin
//we only want valid network cards that are enabled
Strings.Add(pUser.pszwName);
IdList.Add(GuidToString(pUser.guidId));
end;
end;
end;
function TDXCommdlg.GetMacAddress(CardID: string): String;
var
Reg: TRegistry;
KeyValues: TSTringList;
i: integer;
CardInstanceID,CardAddress: string;
begin
Result := '';
Reg := TRegistry.Create;
KeyValues := TStringList.Create;
try
Reg.RootKey:=HKEY_LOCAL_MACHINE;
if Reg.OpenKey(MacLocation,false) then
begin
Reg.GetKeyNames(KeyValues);
Reg.CloseKey;
for i := 0 to KeyValues.Count-1 do
if reg.OpenKey(MacLocation+'\'+KeyValues[i],false) then
begin
CardInstanceID := Reg.ReadString('NetCfgInstanceId');
CardAddress := Reg.ReadString('NetworkAddress');
Reg.CloseKey;
if CardInstanceID = CardId then
begin
if CardAddress='' then CardAddress := 'Hardware';
Result := CardAddress;
break;
end;
end;
end;
finally
Reg.Free;
KeyValues.Free;
end;
end;
procedure TDXCommdlg.ResetNIC(const aConnection: string);
var
pEnum: IEnumVariant;
vNetCon: OleVARIANT;
dwRetrieved: Cardinal;
pUser: NETCONLib_TLB.PUserType1;
begin
enabled := false;
try
pEnum := (NetSharingManager1.EnumEveryConnection._NewEnum as IEnumVariant);
while (pEnum.Next(1, vNetCon, dwRetrieved) = S_OK) do
begin
(IUnknown(vNetCon) as INetConnection).GetProperties(pUser);
if pUser.pszwName = aConnection then
begin
(IUnknown(vNetCon) as INetConnection).Disconnect;
(IUnknown(vNetCon) as INetConnection).Connect;
sleep(2000);
break;
end;
end;
finally
enabled := true;
end;
end;
I thought I had setup my program to run as administrator, but apparently I didn't do it right. Once I did the following, that access denied message went
away.
To run an application one time with a full administrator access token
Locate the program icon or a shortcut in Windows Explorer.
Right-click the program icon or shortcut, and then click Run as
administrator.
When the UAC message is displayed, do one of the following:
If you are logged on as a standard user, or if UAC is configured to
always require credentials, enter the appropriate administrative
credentials, and then click OK.
If you are logged on as an administrator and UAC is not configured
to always require credentials, click Yes to start the application.

How I can list the contents of a folder of a remote machine

I'm looking for a windows api function or another way to get the content (folder and files) of a folder located in a machine on my LAN. off course which I have a valid windows user and password for every machine which I want to access.
You can use the WMI , check the CIM_DataFile and CIM_Directory classes.
Some Notes
1.First you must enable the wmi remote access in the client machines. Read these articles to see how do this and the differences between windows versions Connecting to WMI on a Remote Computer, Securing a Remote WMI Connection.
2.Always you must use filters (Where conditions) to restrict the result of these WMI classes.
3.Always you must use the Drive field as condition, because these classes return the files of all drives.
4.The Wmi interprets the \ (Backslash) character as a reserverd symbol so you must need to escape that character to avoid problems with the WQL sentence.
Delphi Code
{$APPTYPE CONSOLE}
uses
SysUtils,
ActiveX,
ComObj,
Variants;
procedure GetRemoteFolderContent(Const WbemComputer,WbemUser,WbemPassword,Path:string);
const
wbemFlagForwardOnly = $00000020;
var
FSWbemLocator : OLEVariant;
FWMIService : OLEVariant;
FWbemObjectSet: OLEVariant;
FWbemObject : OLEVariant;
oEnum : IEnumvariant;
iValue : LongWord;
WmiPath : string;
Drive : string;
begin;
//The path
//Get the drive
Drive :=ExtractFileDrive(Path);
//get the path and add a backslash to the end
WmiPath :=IncludeTrailingPathDelimiter(Copy(Path,3,Length(Path)));
//escape the backslash character
WmiPath :=StringReplace(WmiPath,'\','\\',[rfReplaceAll]);
Writeln('Connecting');
FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
//Establish the connection
FWMIService := FSWbemLocator.ConnectServer(WbemComputer, 'root\CIMV2', WbemUser, WbemPassword);
Writeln('Files');
Writeln('-----');
//Get the files from the specified folder
FWbemObjectSet:= FWMIService.ExecQuery(Format('SELECT * FROM CIM_DataFile Where Drive="%s" AND Path="%s"',[Drive,WmiPath]),'WQL',wbemFlagForwardOnly);
oEnum := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
while oEnum.Next(1, FWbemObject, iValue) = 0 do
begin
Writeln(Format('%s',[FWbemObject.Name]));
FWbemObject:=Unassigned;
end;
Writeln('Folders');
Writeln('-------');
//Get the folders from the specified folder
FWbemObjectSet:= FWMIService.ExecQuery(Format('SELECT * FROM CIM_Directory Where Drive="%s" AND Path="%s"',[Drive,WmiPath]),'WQL',wbemFlagForwardOnly);
oEnum := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
while oEnum.Next(1, FWbemObject, iValue) = 0 do
begin
Writeln(Format('%s',[FWbemObject.Name]));
FWbemObject:=Unassigned;
end;
end;
begin
try
CoInitialize(nil);
try
GetRemoteFolderContent('remote_machine','user','password','C:\');
GetRemoteFolderContent('remote_machine','user','password','C:\Program Files');
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.
Without the authorization part, it's simple enough. The right way to do the authorization is to call Windows.pas method WNetAddConnection2 and go that way.
However, because I'm in a simple hack mode, I tried this, and it basically works:
uses Types, IOUtils, ShellApi; // Works in Delphi XE.
procedure TForm5.Button1Click(Sender: TObject);
var
dirs:TStringDynArray;
files:TStringDynArray;
apath, dir,filename:String;
begin
ListBox1.Items.Clear;
apath := '\\hostname\sharename';
// This should be calling WNetAddConnection2:
// instead It's an evil (portable) hack.
ShellExecute(HWND(0), 'open', PChar('net use /delete '+ apath),
nil,nil,SW_SHOW );
ShellExecute(HWND(0), 'open', PChar('net use '+ apath+' /user:uid pswd'),
nil,nil,SW_SHOW );
dirs := TDirectory.GetDirectories(apath);
if Length(dirs)=0 then
ListBox1.Items.Add('None found.')
else
for dir in dirs do
ListBox1.Items.Add('Directory: '+dir);
files := TDirectory.GetFiles(apath);
for filename in files do
ListBox1.Items.Add('File: '+filename );
end;
Abject Apologies for the ugly hack of ShellExecute "net use". (Grin) Note that I have elected to "mount" this shared folder without giving it a drive letter, avoiding the problem of what to do if that drive is already mapped.
Here's a good link with a WNetAddConnection2 code sample that I will link to instead of poaching. It shows a sample of the non-evil way to do it. :-) Then you can use the Directory enumeration code as I have shown above.
I suppose this is included in Warren's answer, but to cut to the chase, IOUtils.TDirectory supports UNCs:
implementation
uses IOUtils,types;
procedure GetFiles;
var
i: integer;
files: TStringDynArray;
begin
files := TDirectory.GetFiles('\\aServer\aPath\aShare\', '*.aFileFilter');
for i := Low(files)to High(files) do
memo1.Lines.Add(files[i]);
end;
etc, etc...

How to retrieve a file from Internet via HTTP?

I want to download a file from Internet and InternetReadFile seem a good and easy solution at the first glance. Actually, too good to be true. Indeed, digging a bit I have started to see that actually there are a lot of issues with it. People are complaining about all kinds of problems when using this code.
Problems could appear because:
the application freezes temporarily until the HTTP server responds
the application freezes temporarily because the Internet connections breaks
the application locks up because the HTTP server never responds
the InternetOpen (I just discovered this recently) MUST be called only once during application life time
I could not find a complete example about how to use it properly and robustly. Does anybody have an idea about how to implement it in a separate thread and with a time out? There is another SIMPLE way to robustly download a file from Internet. Though I don't want to complicate my life with very large libraries like Jedi or even Indy.
function GetFileHTTP (const fileURL, FileName: String): boolean;
CONST
BufferSize = 1024;
VAR
hSession, hURL: HInternet;
Buffer: array[1..BufferSize] of Byte;
BufferLen: DWORD;
f: File;
sAppName: string;
begin
// result := false;
sAppName := ExtractFileName(Application.ExeName) ;
hSession := InternetOpen(PChar(sAppName), INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0) ; { be aware that InternetOpen need only be called once in your application!!!!!!!!!!!!!! }
TRY
hURL := InternetOpenURL(hSession, PChar(fileURL), nil, 0, 0, 0) ;
TRY
AssignFile(f, FileName) ;
Rewrite(f, 1) ;
REPEAT
InternetReadFile(hURL, #Buffer, SizeOf(Buffer), BufferLen);
BlockWrite(f, Buffer, BufferLen)
UNTIL BufferLen = 0;
CloseFile(f) ;
Result:= True;
FINALLY
InternetCloseHandle(hURL)
end
FINALLY
InternetCloseHandle(hSession)
END;
END;
Edit:
This functions checks if Internet connection is available. It seems to work on Win98 also.
{ Are we connected to the Internet? }
function IsConnectedToInternet: Boolean; { Call SHELL32.DLL for Win < Win98 otherwise call URL.dll }
var InetIsOffline: function(dwFlags: DWORD): BOOL; stdcall;
begin
Result:= FALSE;
if IsApiFunctionAvailable('URL.DLL', 'InetIsOffline', #InetIsOffline)
then Result:= NOT InetIsOffLine(0)
else
if IsApiFunctionAvailable('SHELL32.DLL', 'InetIsOffline', #InetIsOffline)
then Result:= NOT InetIsOffLine(0)
end;
I am using Delphi 7. Many thanks.
Edit:
Losing customers because the application hangs at the first start up is the perfect recipe for losing money.
Writing your code to be Microsoft platform dependent is bad. You never know if the customer has the IE version x.x installed.
Installing stuff into a user's computer is like playing with guns. It will backfire.
(see more about this here: http://thesunstroke.blogspot.com/2010/06/programmig-like-there-is-no-ms-windows.html)
I basically do the same as you do. For me it works fairly flawlessly.
The only differences between my code and your code is I have an INTERNET_FLAG_RELOAD parameter to force a download from the file and not the cache. You can try that and see if it works better:
hURL := InternetOpenURL(hSession, PChar(fileURL), nil, 0, INTERNET_FLAG_RELOAD, 0) ;
Also check for an internet connection before downloading. Do this:
dwConnectionTypes := INTERNET_CONNECTION_MODEM
+ INTERNET_CONNECTION_LAN
+ INTERNET_CONNECTION_PROXY;
InternetConnected := InternetGetConnectedState(#dwConnectionTypes, 0);
if InternetConnected then ...
Here's some sample code that uses Indy. This code is for Delphi 2010 (with Indy 10?), but the code for Delphi 7 would be similar. I've used Indy for years with D7 and have been very happy with it. I think in D7 we use Indy 9. Check if you need to download a new version...
You can use OnWork and OnWorkBegin to add a progress meter if you need to.
This code I excerpted from a bigger piece, editing it a bit. I did not try compiling it, but it will give you a good starting place.
function Download( const aSourceURL: String;
const aDestFileName: String;
out aDownloadResult: TDownloadResult;
out aErrm: String): boolean;
var
Stream: TMemoryStream;
IDAntiFreeze: TIDAntiFreeze;
begin
aDownloadResult := DROther;
Result := FALSE;
fIDHTTP := TIDHTTP.Create;
fIDHTTP.HandleRedirects := TRUE;
fIDHTTP.AllowCookies := FALSE;
fIDHTTP.Request.UserAgent := 'Mozilla/4.0';
fIDHTTP.Request.Connection := 'Keep-Alive';
fIDHTTP.Request.ProxyConnection := 'Keep-Alive';
fIDHTTP.Request.CacheControl := 'no-cache';
IDAntiFreeze := TIDAntiFreeze.Create;
Stream := TMemoryStream.Create;
try
try
fIDHTTP.Get(aSourceURL, Stream);
if FileExists(aDestFileName) then
DeleteFile(PWideChar(aDestFileName));
Stream.SaveToFile(aDestFileName);
Result := TRUE;
aDownloadResult :=drSuccess;
except
On E: Exception do
begin
Result := FALSE;
aErrm := E.Message + ' (' + IntToStr(fIDHTTP.ResponseCode) + ')';
end;
end;
finally
Stream.Free;
IDAntiFreeze.Free;
fIDHTTP.Free;
end;
end; { Download }
My personal favorite is using the WebHttpRequest component from importing the "Microsoft WinHTTP Services" type library: http://yoy.be/item.asp?i142
var
w:IWebHttpRequest;
f:TFileStream;
os:TOleStream;
begin
w:=CoWebHttpRequest.Create;
w.Open('GET',SourceURL,false);
w.Send(EmptyParam);
os:=TOleStream.Create(IUnknown(w.ResponseStream) as IStream);
f:=TFileStream.Create(DestinationFilePath,fmCreate);
os.Position:=0;
f.CopyFrom(os,os.Size);
f.Free;
os.Free;
w:=nil;
end;
I recommend Synapse. It's small, stable and easy-to-use (no need of any external libraries).
Example from httpsend.pas
function HttpGetText(const URL: string; const Response: TStrings): Boolean;
var
HTTP: THTTPSend;
begin
HTTP := THTTPSend.Create;
try
Result := HTTP.HTTPMethod('GET', URL);
if Result then
Response.LoadFromStream(HTTP.Document);
finally
HTTP.Free;
end;
end;
Instead of fiddling with the WinAPI, the ExtActns unit provides just what you need for downloading to a file.
procedure TMainForm.DownloadFile(URL: string; Dest: string);
var
dl: TDownloadURL;
begin
dl := TDownloadURL.Create(self);
try
dl.URL := URL;
dl.FileName := Dest;
dl.ExecuteTarget(nil); //this downloads the file
dl.Free;
except
dl.Free;
end;
end;
Under the hood, it uses URLDownloadToFile from the URLMon library - which is part of IE, and therefore part of Windows.
TDownloadURL doesn't handle any timeout for you - it doesn't look like such a thing is supported in URLMon at all, although there could be some default timeout that causes the call to fail - but you could use the OnProgress event on TDownloadURL to get notified when something happens, and then do something in another thread if it's been too long since the last callback.
Solved using improved version of the above code.
(it still does not solve all issues - MS does not actually implemented full support for server time out)
The connection does not timeout while downloading file from internet

Problems reading registry from Delphi 7 on Windows 7 64 bit

I think this question was already asked, but I couldn't find a solution which works for me. I use Delphi 7 under Windows 7 Ultimate, 64 bit. Actually I started writing application under 32 bit OS, but then changes PC, so now its 64. In my program I use registration process with Licence ID generated from PROGID value of Windows. Unfortunately it doesn't read the value, seems like it is looking in a different folder, probably redirected by Windows 64 to 32 bit registry. Can you help? This is the code I use:
Registry := TRegistry.Create(KEY_READ OR $0100);
try
Registry.Lazywrite := false;
Registry.RootKey := HKEY_LOCAL_MACHINE;
if CheckForWinNT = true then
Begin
if not Registry.OpenKeyReadOnly('\Software\Microsoft\Windows NT\CurrentVersion') then showmessagE('cant open');
end
else
Registry.OpenKeyReadOnly('\Software\Microsoft\Windows\CurrentVersion');
result := Registry.ReadString('ProductID');
Registry.CloseKey;
finally
Registry.Free;
end; // try..finally
Also, do you know how to find whether program is running under 64 bit or 32 bit computer in Delphi 7?
You already asked this question see Registry ReadString method is not working in Windows 7 in Delphi 7.
So you know that you have to add $0100 in the TRegistry.Create. The problem with your code is that you use OpenKeyReadOnly which resets the Access property of the registry to KEY_READ, so KEY_READ or $0100 is lost.
Just use OpenKey instead of OpenKeyReadOnly, this won't reset your Access property.
Here is some Delphi 7 code to detect whether you are running in a 64-bit OS:
function Is64BitOS: Boolean;
type
TIsWow64Process = function(Handle:THandle; var IsWow64 : BOOL) : BOOL; stdcall;
var
hKernel32 : Integer;
IsWow64Process : TIsWow64Process;
IsWow64 : BOOL;
begin
// we can check if the operating system is 64-bit by checking whether
// we are running under Wow64 (we are 32-bit code). We must check if this
// function is implemented before we call it, because some older versions
// of kernel32.dll (eg. Windows 2000) don't know about it.
// see http://msdn.microsoft.com/en-us/library/ms684139%28VS.85%29.aspx
Result := False;
hKernel32 := LoadLibrary('kernel32.dll');
if (hKernel32 = 0) then RaiseLastOSError;
#IsWow64Process := GetProcAddress(hkernel32, 'IsWow64Process');
if Assigned(IsWow64Process) then begin
IsWow64 := False;
if (IsWow64Process(GetCurrentProcess, IsWow64)) then begin
Result := IsWow64;
end
else RaiseLastOSError;
end;
FreeLibrary(hKernel32);
end;
(Shamelessly plagiarized from myself, here)
It looks like you are passing KEY_WOW64_64KEY ($0100), so you should be looking at the 64-bit registry branch. If you want to look at the 32-bit registry branch, you should pass KEY_WOW64_32KEY ($0200).
As to your side question, whether it's a 64-bit computer (which is not the same thing as running on a 64-bit OS), have a look at the answers to this question.
I know this topic is about delphi 7, but I thought I was having problems reading the registry and came here to learn.. I ended up using Key_Read instead of all the extras suggested here.
I'm using Delphi 2010 and I used Key_Read just fine.
Here is my part of my source that works:
//Search registry
reg:=TRegistry.Create(KEY_READ);
with reg do begin
try
RootKey := HKEY_LOCAL_MACHINE;
if OpenKey('\SOFTWARE\Wow6432Node\Blizzard Entertainment\World of Warcraft',false) then
begin
memo.Lines.Add('HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Blizzard Entertainment\World of Warcraft - exists');
wowdir1 := readstring('InstallPath');
memo.Lines.Add('InstallPath - ' + wowdir1);
newline;
closekey;
end;
if OpenKey('\SOFTWARE\Wow6432Node\Blizzard Entertainment\World of Warcraft',false) then
begin
memo.Lines.Add('HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Blizzard Entertainment\World of Warcraft - exists');
wowdir2 := readstring('GamePath');
memo.Lines.Add('GamePath - ' + wowdir2);
newline;
wowdir1 := readstring('');
closekey;
end;
if OpenKey('\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\World of Warcraft',false) then
begin
memo.Lines.Add'HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\World of Warcraft - exists');
wowdir3 := readstring('InstallLocation');
memo.Lines.Add('InstallLocation - ' + wowdir3);
newline;
wowdir1 := readstring('');
closekey;
end;
finally
reg.Free;
end;
I tried the other Keys that are displayed here and found I don't need KEY_WOW64_64KEY OR KEY_WOW64_32KEY. This must have been a bug that has been corrected in Delphi 2010.

Resources