Code works in Delphi 7 but not in Delphi 2010 [Edit]

hello,
i have a procedure that open's a file by passing the file name as the parameter to the executable.
something like this
{code}
  C : \ P r o g r a m   F i l e s \ Da c k e r \ D r a c k e r . e x e   " G : \ D E l p h i   7 \ D e l p h i 7 A p p _ l o g . t "
{code}
The source code is 
{code}
     procedure OpenFileWithExe
var
  hReg: HKEY;
  Ret: Longint;
  RegDataType, RegDataSize: DWORD;
  CmdLine: array [0..560] of Char;
  Len: Integer;
  SInfo: TStartupInfo;
  PInfo: TProcessInformation;
begin
  Ret := windows.RegOpenKeyEx(HKEY_CURRENT_USER,
                  'SOFTWARE\Dracker',
                  0, KEY_READ, hReg);
  RegDataType := REG_SZ;
  RegDataSize := 260;
  Ret := windows.RegQueryValueEx(hReg,'Installation_path',nil, @RegDataType, @CmdLine, @RegDataSize);
  RegCloseKey(hReg);
  CmdLine[RegDataSize - 1] := ' ';
  CmdLine[RegDataSize] := '"';    
  Len := windows.GetModuleFileName(0,PChar(@CmdLine[RegDataSize + 1]), 260) + RegDataSize;
  while CmdLine[Len] <> '.' do    
    Dec(Len);
  CmdLine[Len] := #0;
  lstrcat(CmdLine, '_file_leak_log.umlt"'#0); 
  ZeroMemory(@SInfo, SizeOf(SInfo));
  SInfo.cb := SizeOf(SInfo);
  CreateProcess(nil, CmdLine, nil, nil, False,NORMAL_PRIORITY_CLASS, nil, nil, sInfo, pInfo);
end;
{code}
This works fine in delphi 7. the code open the exe with the file path/name as the paramter but the same code doesnt work in Delphi 2010

in Dlephi 2010 the the value of CmdLine is 
{code}
(C : \ P r o g r a m   F i l e s \ D a c k e r \ D a c k e r . e x e __ l o g . t " #0 #0 #0 #0 #0 #0 #0 #0 #0 #0 #0 #0 #0 #0 #0 #0 #0 #0 #0 #0 
#0 #0 #0 #0   " G : \ D E l p h i   2 0 1 0 \ D e l p h i 2 0 1 0 A p p #0 e x e
{code}
i guess the 
{code}
  windows.GetModuleFileName
{code}
is not getting the exe  directory?
Edited by: Presley Dias on Jul 19, 2012 6:00 AM
Edited by: Presley Dias on Aug 30, 2012 6:03 AM
0
Presley
8/30/2012 1:04:39 PM
📁 embarcadero.delphi.non-tech
📃 5933 articles.
⭐ 1 followers.

💬 7 Replies
👁️‍🗨️ 2637 Views


Try with Widechar and PWidechar with the lines below.
{code}
CmdLine: array [0..560] of Char;
{code}
and
{code}
Len := windows.GetModuleFileName(0,PChar(@CmdLine[RegDataSize + 1]),
60)+ RegDataSize;
{code}
0
Adem
7/19/2012 2:41:40 PM
Adem wrote:
> Len := windows.GetModuleFileName(0,PChar(@CmdLine[RegDataSize + 1]),
> 60)+ RegDataSize;
RegDataSize is expressed in bytes, not in Chars.  SizeOf(WideChar) is 2, 
so you need to account for that.
--
Remy Lebeau (TeamB)
0
Remy
7/19/2012 4:40:19 PM
Presley wrote:
> This works fine in delphi 7. the code open the exe with the file
> path/name as the paramter but the same code doesnt work in Delphi 2010
That is because Char mapped to AnsiChar in D7 but now maps to WideChar in 
D2009+.  Your code is not taking that into account.
I would suggest a slightly different approach.  Use a Char array just to 
retreive the Registry value, and then use a String for everything else.  
This should work in both D7 and D2010:
{code:delphi}
uses
  ..., SysUtils, Windows;
procedure OpenFileWithExe;
var
  hReg: HKEY;
  Ret: Longint;
  RegDataType, RegDataSize: DWORD;
  InstallPath: array [0..MAX_PATH] of Char;
  CmdLine: String;
  Len: Integer;
  SInfo: TStartupInfo;
  PInfo: TProcessInformation;
begin
  Ret := RegOpenKeyEx(HKEY_CURRENT_USER, 'SOFTWARE\leakTracker', 0, KEY_QUERY_VALUE, 
hReg);
  if Ret <> 0 then Exit;
  ZeroMemory(@InstallPath, SizeOf(InstallPath));
  RegDataType := REG_SZ;
  RegDataSize := SizeOf(InstallPath);
  Ret := RegQueryValueEx(hReg, 'Installation_path', nil, @RegDataType, @InstallPath, 
@RegDataSize);
  RegCloseKey(hReg);
  if Ret <> 0 then Exit;
  CmdLine := String(InstallPath) + ' "' + ChangeFileExt(ParamStr(0), '') 
+ '_file_leak_log.umlt"';
  ZeroMemory(@SInfo, SizeOf(SInfo));
  SInfo.cb := SizeOf(SInfo);
  ZeroMemory(@PInfo, SizeOf(PInfo));
  if CreateProcess(nil, PChar(CmdLine), nil, nil, False, NORMAL_PRIORITY_CLASS, 
nil, nil, SInfo, PInfo) then
  begin
    CloseHandle(PInfo.hThread);
    CloseHandle(PInfo.hProcess);
  end;
end;
{code}
--
Remy Lebeau (TeamB)
0
Remy
7/19/2012 5:00:55 PM
Presley wrote:
> but i get *Runtime error 203 at 004029f8* at +sExename :=ParamStr(0);+
> .  (Heap overflow error)
That line is allocating a new Delphi string on the heap.  If that line is 
failing at runtime, then this code is most likely being called in a spot 
that is not allowed to allocate any memory from the RTL at all.  That would 
explain why the original code was coded the way it was, using a single static 
array to hold everything.  If that is the case, then let's go back to the 
original code and make it work with D2010 correctly:
{code:delphi}
procedure OpenFileWithExe;
var
  hReg: HKEY;
  Ret: Longint;
  RegDataType, RegDataSize: DWORD;
  CmdLine: array [0..((MAX_PATH*2)+40)] of Char;
  Len: DWORD;
  SInfo: TStartupInfo;
  PInfo: TProcessInformation;
begin
  ZeroMemory(@CmdLine, SizeOf(CmdLine));
  Ret := RegOpenKeyEx(HKEY_CURRENT_USER, 'SOFTWARE\leakTracker', 0, KEY_QUERY_VALUE, 
hReg);
  if Ret <> 0 then Exit;
  RegDataType := REG_SZ;
  RegDataSize := MAX_PATH * SizeOf(Char);
  Ret := RegQueryValueEx(hReg, 'Installation_path', nil, @RegDataType, @CmdLine, 
@RegDataSize);
  RegCloseKey(hReg);
  if Ret <> 0 then Exit;
  lstrcat(CmdLine, ' "');
  Len := lstrlen(CmdLine);
  Inc(Len, GetModuleFileName(0, @CmdLine[Len], MAX_PATH));
  while CmdLine[Len-1] <> '.' do
    Dec(Len);
  CmdLine[Len-1] := #0;
  lstrcat(CmdLine, '_file_leak_log.umlt"');
  ZeroMemory(@SInfo, SizeOf(SInfo));
  SInfo.cb := SizeOf(SInfo);
  ZeroMemory(@PInfo, SizeOf(PInfo));
  if CreateProcess(nil, CmdLine, nil, nil, False,NORMAL_PRIORITY_CLASS, nil, 
nil, SInfo, PInfo) then
  begin
    CloseHandle(PInfo.hThread);
    CloseHandle(PInfo.hProcess);
  end;
end;
{code}
--
Remy Lebeau (TeamB)
0
Remy
7/23/2012 12:53:48 AM
> {code:delphi}
> uses
>   ..., SysUtils, Windows;
> 
> procedure OpenFileWithExe;
> var
>   hReg: HKEY;
>   Ret: Longint;
>   RegDataType, RegDataSize: DWORD;
>   InstallPath: array [0..MAX_PATH] of Char;
>   CmdLine: String;
>   Len: Integer;
>   SInfo: TStartupInfo;
>   PInfo: TProcessInformation;
> begin
>   Ret := RegOpenKeyEx(HKEY_CURRENT_USER, 'SOFTWARE\Dracker', 0, KEY_QUERY_VALUE, 
> hReg);
>   if Ret <> 0 then Exit;
>   ZeroMemory(@InstallPath, SizeOf(InstallPath));
>   RegDataType := REG_SZ;
>   RegDataSize := SizeOf(InstallPath);
>   Ret := RegQueryValueEx(hReg, 'Installation_path', nil, @RegDataType, @InstallPath, 
> @RegDataSize);
>   RegCloseKey(hReg);
>   if Ret <> 0 then Exit;
>   CmdLine := String(InstallPath) + ' "' + ChangeFileExt(ParamStr(0), '') 
> + '_file_leak_log.umlt"';
>   ZeroMemory(@SInfo, SizeOf(SInfo));
>   SInfo.cb := SizeOf(SInfo);
>   ZeroMemory(@PInfo, SizeOf(PInfo));
>   if CreateProcess(nil, PChar(CmdLine), nil, nil, False, NORMAL_PRIORITY_CLASS, 
> nil, nil, SInfo, PInfo) then
>   begin
>     CloseHandle(PInfo.hThread);
>     CloseHandle(PInfo.hProcess);
>   end;
> end;
> {code}

hello,  Thank you for the solution..but there is a little problem.See the above code is being used in FASTmm4, so i cannot use SysUtils in fastmm4. so i slighlty modified the your code as this to account for ChangeFileExt without using SysUtils  as
{code}
procedure OpenFileWithExe;
var
  hReg: HKEY;
  Ret: Longint;
  RegDataType, RegDataSize: DWORD;
  InstallPath           : array [0..MAX_PATH] of Char;
  CmdLine               : String;
  SInfo                 : TStartupInfo;
  PInfo                 : TProcessInformation;
  sExename              : string;
  sNAmeWithoutExTension : string;
begin
  sExename :=ParamStr(0);
  sNAmeWithoutExTension :=copy(sExename,0,length(sExename)-4);
  Ret := RegOpenKeyEx(HKEY_CURRENT_USER, 'SOFTWARE\Dracker', 0, KEY_QUERY_VALUE,
hReg);
  if Ret <> 0 then Exit;
  ZeroMemory(@InstallPath, SizeOf(InstallPath));
  RegDataType := REG_SZ;
  RegDataSize := SizeOf(InstallPath);
  Ret := RegQueryValueEx(hReg, 'Installation_path', nil, @RegDataType, @InstallPath,
@RegDataSize);
  RegCloseKey(hReg);
  if Ret <> 0 then Exit;
  CmdLine := String(InstallPath) + ' "' + {ChangeFileExt(ParamStr(0), '')}sNAmeWithoutExTension
+ '_f_log.t"';
  ZeroMemory(@SInfo, SizeOf(SInfo));
  SInfo.cb := SizeOf(SInfo);
  ZeroMemory(@PInfo, SizeOf(PInfo));
  if CreateProcess(nil, PChar(CmdLine), nil, nil, False, NORMAL_PRIORITY_CLASS,
nil, nil, SInfo, PInfo) then
  begin
    CloseHandle(PInfo.hThread);
    CloseHandle(PInfo.hProcess);
  end;
end;
{code}
but i get *Runtime error 203 at 004029f8* at +sExename :=ParamStr(0);+ .  (Heap overflow error)

Now to get the exe name i also tried this 
{code}
function GetModuleName: string;
var
  szFileName: array[0..MAX_PATH] of Char;
begin
  FillChar(szFileName, SizeOf(szFileName), #0);
  GetModuleFileName(hInstance, szFileName, MAX_PATH);
  Result := szFileName;
end;
{code}
and 
{code}
  procedure OpenFileWithExe;
var
  ..
  ..
begin
  sExename :=GetModuleName;
  sNAmeWithoutExTension :=copy(sExename,0,length(sExename)-4);
....
...
...
{code}
but stil the same error comes  *Runtime error 203 at 004029f8*  at *  Result := szFileName;*
any ways to solve this?
Edited by: Presley Dias on Aug 30, 2012 6:05 AM
0
Presley
8/30/2012 1:06:38 PM
In D2010 a Char is 2 bytes in size. So if RegDataSize contains the size 
of the string, it contains only half of that characters.
-- 
Uwe Raabe
Embarcadero MVP
Uwe's Blog: The Art of Delphi Programming <http://www.uweraabe.de/>
0
Uwe
8/30/2012 2:28:11 PM
Presley Dias wrote:
> hello,
> i have a procedure that open's a file by passing the file name as the parameter to the executable.
> something like this
> 
> {code}
>   C : \ P r o g r a m   F i l e s \ Da c k e r \ D r a c k e r . e x e   " G : \ D E l p h i   7 \ D e l p h i 7 A p p _ l o g . t "
> {code}
> 
> The source code is 
> 
> {code}
>      procedure OpenFileWithExe
> var
>   hReg: HKEY;
>   Ret: Longint;
>   RegDataType, RegDataSize: DWORD;
>   CmdLine: array [0..560] of Char;  
 > begin
 > ...
>   Len := windows.GetModuleFileName(0,PChar(@CmdLine[RegDataSize + 1]), 260) + RegDataSize;
> 
RegDataSize will be the amount of bytes, but you are accessing the bytes div 2th 
caracter.  Char is now unicode so in D7
CmdLine: array [0..560] of Char;
561 bytes long and the regDatasize returned in
  Ret := windows.RegQueryValueEx(hReg,'Installation_path',nil, @RegDataType, 
@CmdLine, @RegDataSize);
was a 1:1 to position of the elements in the array.  In D2010 Char is now 
Unicode so 2 bytes big so the size of the array is 1122 bytes and RegDataSize = 
twice the size of the #of characters returned.
So for
C:\Program Files\Dacker\Dracker.exe
in D7 RegDataType returned 36 and you wanted to start at element 37.  In D2010, 
since it is using the RegQueryValueExW version of the call, RegDataSize will be 
coming back 72 and your code is starting at element 73 of your array which is 
wrong.  You still want to start at element 37 of the array in the call to 
GetModuleName
   Len := Winapi.Windows.GetModuleFileName(0,PChar(@CmdLine[trunc(RegDataSize / 
sizeof(Char)) + 1]), 260) + RegDataSize;
should get it right.
-- 
Jeff Overcash (TeamB)
       (Please do not email me directly unless  asked. Thank You)
And so I patrol in the valley of the shadow of the tricolor
I must fear evil. For I am but mortal and mortals can only die.
Asking questions, pleading answers from the nameless
faceless watchers that stalk the carpeted  corridors of Whitehall.
              (Fish)
0
Jeff
8/30/2012 5:14:15 PM
Reply: