Error: (4025) Incompatible type for arg no. 1: Got "_SYSTEMTIME", expected "TSystemTime" - delphi-7

I had such a problem with TSystemTime! There is a project in Delphi 7 that works great! I translate this program into Android, so the choice fell on Lazarus, since it has the ability to program under the platform I need.
When I started to run the program under Android, the compiler began to swear on Windows.pas which is used there. I sawed it out completely and just added the type, const, procedure, function I needed to the project and here the most interesting thing began ...
Here is the part of the code where the errors are:
function NowUTC: TDateTime;
var
st: TSystemTime;
begin
Uninit(st);
GetSystemTime(st);
result := SystemTimeToDateTime(st); //error
end;
function UtcToLocal(utcTime: TDateTime): TDateTime;
var
st: TSystemTime;
lt: TSystemTime;
begin
DateTimeToSystemTime(utcTime, st); <- error
Uninit(lt);
SystemTimeToTzSpecificLocalTime(nil, st, lt);
result := SystemTimeToDateTime(lt); <- error
end;
function LocalToUTC(localTime: TDateTime): TDateTime;
var
inverseTZ: TTimeZoneInformation;
st: TSystemTime;
ut: TSystemTime;
begin
DateTimeToSystemTime(localTime, st); <- error
Uninit(inverseTZ);
GetTimezoneInformation(inverseTZ);
inverseTZ.Bias := -inverseTZ.Bias;
inverseTZ.DaylightBias := -inverseTZ.DaylightBias;
Uninit(ut);
SystemTimeToTzSpecificLocalTime(#inverseTZ, st, ut);
result := SystemTimeToDateTime(ut); <- error
end;
function UtcDateTimeToFiletime(utcDateTime: TDateTime): TFileTime;
var
st: TSystemTime;
begin
DateTimeToSystemTime(utcDateTime, st); <- error
Uninit(result);
SystemTimeToFileTime(st, result);
end;
function FileTimeToLocalDateTime(const ft: TFileTime): TDateTime;
var
st: TSystemTime;
lft: TFileTime;
begin
Uninit(lft);
FileTimeToLocalFileTime(ft, lft);
Uninit(st);
FileTimeToSystemTime(lft, st);
result := SystemTimeToDateTime(st); <- error
end;
And the compiler shows such errors:
Error: (4025) Incompatible type for arg no. 1: Got "_SYSTEMTIME", expected "TSystemTime"
Error: (3069) Call by var for arg no. 2 has to match exactly: Got "_SYSTEMTIME" expected "TSystemTime"
Error: (4025) Incompatible type for arg no. 1: Got "_SYSTEMTIME", expected "TSystemTime"
Error: (3069) Call by var for arg no. 2 has to match exactly: Got "_SYSTEMTIME" expected "TSystemTime"
Error: (4025) Incompatible type for arg no. 1: Got "_SYSTEMTIME", expected "TSystemTime"
Error: (3069) Call by var for arg no. 2 has to match exactly: Got "_SYSTEMTIME" expected "TSystemTime"
Error: (4025) Incompatible type for arg no. 1: Got "_SYSTEMTIME", expected "TSystemTime"
Here is the type I use:
{TSystemTime}
{ System time is represented with the following structure: }
PSystemTime = ^TSystemTime;
_SYSTEMTIME = record
wYear: Word;
wMonth: Word;
wDayOfWeek: Word;
wDay: Word;
wHour: Word;
wMinute: Word;
wSecond: Word;
wMilliseconds: Word;
end;
{$EXTERNALSYM _SYSTEMTIME}
TSystemTime = _SYSTEMTIME;
SYSTEMTIME = _SYSTEMTIME;
{$EXTERNALSYM SYSTEMTIME}
In the type it is written that it is the same (TSystemTime = _SYSTEMTIME) Help please understand. Well and in addition procedure, function which I took from Windows.pas, can helps ...
procedure GetSystemTime(var lpSystemTime: TSystemTime); stdcall;
{$EXTERNALSYM GetSystemTime}
procedure GetSystemTimeAsFileTime(var lpSystemTimeAsFileTime: TFileTime); stdcall;
{$EXTERNALSYM GetSystemTimeAsFileTime}
function SetSystemTime(const lpSystemTime: TSystemTime): BOOL; stdcall;
{$EXTERNALSYM SetSystemTime}
procedure GetLocalTime(var lpSystemTime: TSystemTime); stdcall;
{$EXTERNALSYM GetLocalTime}
function SetLocalTime(const lpSystemTime: TSystemTime): BOOL; stdcall;
{$EXTERNALSYM SetLocalTime}
function GetSystemTimeAdjustment(var lpTimeAdjustment, lpTimeIncrement: DWORD;
var lpTimeAdjustmentDisabled: BOOL): BOOL; stdcall;
{$EXTERNALSYM GetSystemTimeAdjustment}
function SystemTimeToTzSpecificLocalTime(lpTimeZoneInformation: PTimeZoneInformation;
var lpUniversalTime, lpLocalTime: TSystemTime): BOOL; stdcall;
{$EXTERNALSYM SystemTimeToTzSpecificLocalTime}
function GetTimeZoneInformation(var lpTimeZoneInformation: TTimeZoneInformation): DWORD; stdcall;
{$EXTERNALSYM GetTimeZoneInformation}
function SetTimeZoneInformation(const lpTimeZoneInformation: TTimeZoneInformation): BOOL; stdcall;
{$EXTERNALSYM SetTimeZoneInformation}
function SystemTimeToFileTime(const lpSystemTime: TSystemTime; var lpFileTime: TFileTime): BOOL; stdcall;
{$EXTERNALSYM SystemTimeToFileTime}
function FileTimeToLocalFileTime(const lpFileTime: TFileTime; var lpLocalFileTime: TFileTime): BOOL; stdcall;
{$EXTERNALSYM FileTimeToLocalFileTime}
function LocalFileTimeToFileTime(const lpLocalFileTime: TFileTime; var lpFileTime: TFileTime): BOOL; stdcall;
{$EXTERNALSYM LocalFileTimeToFileTime}
function FileTimeToSystemTime(const lpFileTime: TFileTime; var lpSystemTime: TSystemTime): BOOL; stdcall;
{$EXTERNALSYM FileTimeToSystemTime}
procedure OutputDebugString(lpOutputString: PChar); stdcall;
{$EXTERNALSYM OutputDebugString}

You don't post anything compilable (missing using clauses etc), so the first step would to throw all this away and reduce the problem to something minimal.
That said however, if you declare tsystemtime yourself, and then pass it to a windows unit routine that expects the type declared in the windows unit, then no wonder that it doesn't work.

Related

Returning result from Windows callback in 64-bit XE6

I have some code which uses EnumFontFamiliesEX to determine whether a particular font (using its "facename") is installed. The code was working fine in 32-bit. When I compile and run it as 64-bit, it kept throwing an exception in the callback routine.
I have now gotten it to work under both BUT only if instead of passing the function FindFontbyFaceName's result as the 4th parameter to EnumFontFamiliesEX, I pass a local (or global) variable - MYresult in this case. (And then set result from it). I don't understand what is going on? Can anyone explain or point me to a better way. (I'm not so much interested in the mechanics of the fonts, as the basic callback mechanics).
// single font find callback
function FindFontFace( {$IFDEF CPUX86} lpelf: PLogFont; {$ENDIF}
{$IFDEF CPUX64} lpelf: PEnumLogFontEx; {$ENDIF}
lpntm: PNewTextMetricEx;
AFontType: DWORD; var Aresult: lparam): integer ; stdcall;
begin
result := 0; // 1 shot only please - not interested in any variations in style etc
if (lpelf <> nil) then
Aresult := -1 // TRUE
else
Aresult := 0;
end;
function FindFontbyFaceName(ACanvas: TCanvas; const AFacename: string): boolean;
var
lf: TLogFont;
Myresult: boolean;
begin
MYresult := false;
FillChar(lf, SizeOf(lf), 0);
StrLCopy(lf.lfFaceName, PChar(AFacename), 32);
lf.lfCharSet := DEFAULT_CHARSET;
// this works in both 32 and 64 bit
EnumFontFamiliesEX(ACanvas.Handle, lf, #FindFontFace, lparam(#MYresult), 0);
result := MYresult;
// this works in 32 bit but throws exception in callback in 64 bit
// EnumFontFamiliesEX(ACanvas.Handle, lf, #FindFontFace, lparam(#result), 0);
end;
function FindFont(const AFacename: string): boolean;
var
AImage: TImage;
begin
AImage := Timage.Create(nil);
try
result := FindFontbyFaceName(AImage.Canvas, Afacename);
finally
Aimage.Free;
end;
end;
Your callback function is not declared correctly. You are declaring the last parameter as a var LPARAM, which is wrong. The lParam parameter is passed by value, not by reference. When calling EnumFontFamiliesEx() you are passing a pointer to a Boolean as the lParam value.
Your callback is trying to write sizeof(LPARAM) number of bytes to a memory address that only has SizeOf(Boolean) bytes available (and why are you trying to write a -1 to a Boolean?). So you are overwriting memory. When using a pointer to a local variable as the lParam, you are likely just overwriting memory on the calling function's call stack that does not really matter, so you don't see a crash.
You need to either:
remove the var and typecast the lParam parameter to a PBoolean:
function FindFontFace( lpelf: PLogFont;
lpntm: PTextMetric;
FontType: DWORD;
lParam: LPARAM): Integer ; stdcall;
begin
PBoolean(lParam)^ := True;
Result := 0; // 1 shot only please - not interested in any variations in style etc
end;
Or:
function FindFontFace( lpelf: PLogFont;
lpntm: PTextMetric;
FontType: DWORD;
lParam: PBoolean): Integer ; stdcall;
begin
lParam^ := True;
Result := 0; // 1 shot only please - not interested in any variations in style etc
end;
leave the var but change the parameter type to Boolean instead of LPARAM:
function FindFontFace( var lpelf: TLogFont;
var lpntm: TTextMetric;
FontType: DWORD;
var lParam: Boolean): Integer ; stdcall;
begin
lParam := True;
Result := 0; // 1 shot only please - not interested in any variations in style etc
end;
Either approach will allow you to pass #Result as the lParam to EnumFontFamiliesEx() in both 32bit and 64bit:
function FindFontbyFaceName(ACanvas: TCanvas; const AFacename: string): Boolean;
var
lf: TLogFont;
begin
Result := False;
FillChar(lf, SizeOf(lf), 0);
StrLCopy(lf.lfFaceName, PChar(AFacename), 32);
lf.lfCharSet := DEFAULT_CHARSET;
EnumFontFamiliesEX(ACanvas.Handle, lf, #FindFontFace, LPARAM(#Result), 0);
end;
On a side note, creating a TImage just to have a canvas to enumerate with is wasteful. You don't need it at all:
function FindFontFace( lpelf: PLogFont;
lpntm: PTextMetric;
FontType: DWORD;
lParam: LPARAM): integer ; stdcall;
begin
PBoolean(lParam)^ := True;
Result := 0; // 1 shot only please - not interested in any variations in style etc
end;
function FindFont(const AFacename: string): Boolean;
var
lf: TLogFont;
DC: HDC;
begin
Result := False;
FillChar(lf, SizeOf(lf), 0);
StrLCopy(lf.lfFaceName, PChar(AFacename), 32);
lf.lfCharSet := DEFAULT_CHARSET;
DC := GetDC(0);
EnumFontFamiliesEx(DC, lf, #FindFontFace, LPARAM(#Result), 0);
ReleaseDC(0, DC);
end;
That being said, you can simplify the code if you use the TScreen.Fonts property instead of calling EnumFontFamiliesEx() directly:
function FindFont(const AFacename: string): Boolean;
begin
Result := (Screen.Fonts.IndexOf(AFacename) <> -1);
end;

Check for existence of a shortcut pointing to a specific target in Inno Setup

In my Inno Setup installer I need to make sure a shortcut to a certain file is present in a folder. The name of the shortcut is arbitrary and not under my control. I only know which file it needs to point to. If the shortcut is missing, I need to generate the shortcut. If it is already present, it must not be created again.
I guess that it is somehow possible to iterate through all shortcut files in the relevant folder and check which file they point to. In a comment to an answer to Shared Shortcuts/Icons, a IShellLink interface is mentioned, but I don’t know how to make it available in the Code section. (Uses ShlObj; is not recognized)
Does anybody have a suggestion how I could solve this problem?
Based on
the official Inno Setup CodeAutomation2.iss example and
deleted answer by #TLama to How to get shortcut target path with InnoSetup.
Requires Unicode version of Inno Setup (the only version as of Inno Setup 6).
const
MAX_PATH = 260;
STGM_READ = $00000000;
SLGP_SHORTPATH = $1;
SLGP_RAWPATH = $4;
SLGP_RELATIVEPRIORITY = $8;
CLSID_ShellLink = '{00021401-0000-0000-C000-000000000046}';
type
TWin32FindDataW = record
dwFileAttributes: DWORD;
ftCreationTime: TFileTime;
ftLastAccessTime: TFileTime;
ftLastWriteTime: TFileTime;
nFileSizeHigh: DWORD;
nFileSizeLow: DWORD;
dwReserved0: DWORD;
dwReserved1: DWORD;
cFileName: array[0..MAX_PATH-1] of Char;
cAlternateFileName: array[0..13] of Char;
end;
IShellLinkW = interface(IUnknown)
'{000214F9-0000-0000-C000-000000000046}'
function GetPath(pszFile: string; cchMaxPath: Integer;
var FindData: TWin32FindDataW; fFlags: DWORD): HRESULT;
procedure Dummy2;
procedure Dummy3;
function GetDescription(pszName: string; cchMaxName: Integer): HRESULT;
function SetDescription(pszName: string): HRESULT;
function GetWorkingDirectory(pszDir: string; cchMaxPath: Integer): HRESULT;
function SetWorkingDirectory(pszDir: string): HRESULT;
function GetArguments(pszArgs: string; cchMaxPath: Integer): HRESULT;
function SetArguments(pszArgs: string): HRESULT;
function GetHotkey(var pwHotkey: Word): HRESULT;
function SetHotkey(wHotkey: Word): HRESULT;
function GetShowCmd(out piShowCmd: Integer): HRESULT;
function SetShowCmd(iShowCmd: Integer): HRESULT;
function GetIconLocation(pszIconPath: string; cchIconPath: Integer;
out piIcon: Integer): HRESULT;
function SetIconLocation(pszIconPath: string; iIcon: Integer): HRESULT;
function SetRelativePath(pszPathRel: string; dwReserved: DWORD): HRESULT;
function Resolve(Wnd: HWND; fFlags: DWORD): HRESULT;
function SetPath(pszFile: string): HRESULT;
end;
IPersist = interface(IUnknown)
'{0000010C-0000-0000-C000-000000000046}'
function GetClassID(var classID: TGUID): HRESULT;
end;
IPersistFile = interface(IPersist)
'{0000010B-0000-0000-C000-000000000046}'
function IsDirty: HRESULT;
function Load(pszFileName: string; dwMode: Longint): HRESULT;
function Save(pszFileName: string; fRemember: BOOL): HRESULT;
function SaveCompleted(pszFileName: string): HRESULT;
function GetCurFile(out pszFileName: string): HRESULT;
end;
function GetLinkFileTarget(const FileName: string): string;
var
FindData: TWin32FindDataW;
ComObject: IUnknown;
ShellLink: IShellLinkW;
PersistFile: IPersistFile;
begin
ComObject := CreateComObject(StringToGuid(CLSID_ShellLink));
PersistFile := IPersistFile(ComObject);
OleCheck(PersistFile.Load(FileName, STGM_READ));
ShellLink := IShellLinkW(ComObject);
SetLength(Result, MAX_PATH);
OleCheck(ShellLink.GetPath(Result, MAX_PATH, FindData, SLGP_RAWPATH));
SetLength(Result, Pos(#0, Result) - 1);
end;
procedure IterateShortcuts(Path: string);
var
FindRec: TFindRec;
ShortcutPath: string;
TargetPath: string;
begin
Path := AddBackslash(Path);
Log(Format('Looking for .lnk in [%s]', [Path]));
if FindFirst(Path + '*.lnk', FindRec) then
begin
try
repeat
ShortcutPath := Path + FindRec.Name;
TargetPath := GetLinkFileTarget(ShortcutPath);
Log(Format('Target of shortcut [%s] is [%s]', [
ShortcutPath, TargetPath]));
until not FindNext(FindRec);
finally
FindClose(FindRec);
end;
end;
end;

How to compile using Free Pascal

Guys I got a source from a friend that is suppose to help me learn RE a lot but I got error
Error:identifier not found "TResourceStream"
"Bool"
"TMemoryStream"
"TResourceInfo"
"try"
And
Fatal: Syntax error, ";" expected but " identifier MS" found
Please help I need to compile this.
Excuse me please I know nothing yet, about programming.
Here is the source
function EnumResourceNames(hModule: HMODULE; // EXE handle returned from LoadLibrary/Ex
lpType: PChar; // resource type (eg: RT_RCDATA)
lpEnumFunc: ENUMRESNAMEPROC; // callback function address
lParam: Integer // long integer (eg: pointer to an object)
): BOOL; stdcall;
function CB_EnumDfmNameProc(hModule: THandle; lpszType, lpszName: PChar;
lParam: Integer): Boolean; stdcall;
var
ms: TMemoryStream;
rs: TResourceStream;
Buffer: array of Byte;
begin
with TResourceInfo(lParam) do
begin
rs := TResourceStream.Create(TResourceInfo(lParam).Module,
lpszname, lpszType); // load resource in memory
try
ms := TMemoryStream.Create;
try
try
SetLength(Buffer, 4);
rs.Read(Buffer[0], SizeOf(Buffer)); // read the first 4 bytes
if string(Buffer) = 'TPF0' then // is it a DFM resource?
begin
rs.Seek(0, 0);
ObjectBinaryToText(rs, ms); // decode DFM
ms.Seek(0, 0);
AddDfm(StrPas(lpszName), ms); // add it to our own list
end;
except
raise;
end;
finally
ms.Free;
end;
finally
rs.free;
end;
end;
Result := True;
end;
procedure TResourceInfo.EnumDfmNames;
begin
if FModule > 0 then // if an EXE file has been loaded
EnumResourceNames(FModule, RT_RCDATA, // go and search RCDATA resources
#CB_EnumDfmNameProc, Integer(Self));
end;

Inno Setup: WaitForSingleObject returns invalid ProcessHandle

When I run this code, the calc.exe starts, but I cannot assign the process handle to a job.
The process starts, but the handle is not valid?
Where did I go wrong?
The result of GetLastError() is always 6.
I followed this tutorial:
Inno Setup Exec() function Wait for a limited time
const
INFINITE= $FFFFFFFF;
SEE_MASK_NOASYNC= $00000100;
SEE_MASK_NOCLOSEPROCESS= $00000040;
type
TShellExecuteInfo = record
cbSize: DWORD;
fMask: Cardinal;
HWND: HWND;
lpVerb: string;
lpFile: string;
lpParameters: string;
lpDirectory: string;
nShow: Integer;
hInstApp: THandle;
lpIDList: DWORD;
lpClass: string;
hkeyClass: THandle;
dwHotKey: DWORD;
hMonitor: THandle;
hProcess: THandle;
end;
function ShellExecuteAndWait(
Filename : String;
Params : String;
WorkingDir : String;
ShowCmd : Integer
) : Integer;
var
JobObject : Thandle;
ExecInfo : TShellExecuteInfo;
ExitCode : DWORD;
begin
ExecInfo.fMask := SEE_MASK_NOCLOSEPROCESS;
ExecInfo.hwnd := 0;
ExecInfo.lpVerb := 'open';
ExecInfo.lpFile := Filename;
ExecInfo.lpParameters := Params;
ExecInfo.lpDirectory := WorkingDir;
ExecInfo.nShow := ShowCmd;
ExecInfo.cbSize := SizeOf(ExecInfo);
JobObject := CreateJobObject( '' , 'WaitJob');
ShellExecuteEx(ExecInfo);
if not AssignProcessToJobObject( JobObject , ExecInfo.hProcess ) then
begin
MsgBox( 'Error during the assign. ' + 'Error code: ' + IntToStr( GetLastError() ), mbConfirmation, MB_OK); //Returns: 6 - Invalid handler
end;
WaitForSingleObject( JobObject , INFINITE );
GetExitCodeProcess( ExecInfo.hProcess , ExitCode );
Result := ExitCode;
end;
EDIT:
More function prototypes.
function WaitForSingleObject(
hHandle : THandle;
dwMilliseconds : DWORD
) : DWORD;
external 'WaitForSingleObject#kernel32.dll stdcall';
function ShellExecuteEx(
lpExecInfo: TShellExecuteInfo
): BOOL;
external 'ShellExecuteEx{#AW}#Shell32.dll stdcall';
function AssignProcessToJobObject(
hJob : Thandle;
hProcess : Thandle
): BOOL;
external 'AssignProcessToJobObject#kernel32.dll stdcall';
function CreateJobObject(
lpSecurityAttributes,
lpName: string
): THandle;
external 'CreateJobObject{#AW}#kernel32.dll stdcall';

How can I use GetVolumeInformation in Inno Setup?

I need to get the volume serial number for a drive letter during an installation created with Inno Setup. I know that DLL functions can be imported into Inno, but I'm fairly new to it and having some problems getting it to work. I know that the GetVolumeInformation function in kernel32 can do what I need. Could someone show me how to import and use that functionality in an Inno script to retrieve the volume serial number?
Thanks!
Inno-Setup code::
[Code]
function GetVolumeInformation(
lpRootPathName: PChar;
lpVolumeNameBuffer: PChar;
nVolumeNameSize: DWORD;
var lpVolumeSerialNumber: DWORD;
var lpMaximumComponentLength: DWORD;
var lpFileSystemFlags: DWORD;
lpFileSystemNameBuffer: PChar;
nFileSystemNameSize: DWORD
): BOOL;
external 'GetVolumeInformationA#kernel32.dll stdcall';
function LoWord(dw: DWORD): WORD;
begin
Result := WORD(dw);
end;
function HiWord(dw: DWORD): WORD;
begin
Result := WORD((dw shr 16) and $FFFF);
end;
function WordToHex(w: WORD): string;
begin
Result := Format('%.4x', [w]);
end;
function FindVolumeSerial(const Drive: string): string;
var
FileSystemFlags: DWORD;
VolumeSerialNumber: DWORD;
MaximumComponentLength: DWORD;
begin
Result := '';
// Note on passing PChars using RemObjects Pascal Script:
// '' pass a nil PChar
// #0 pass an empty PChar
if GetVolumeInformation(
PChar(Drive),
'', // nil
0,
VolumeSerialNumber,
MaximumComponentLength,
FileSystemFlags,
'', // nil
0)
then
Result := WordToHex(HiWord(VolumeSerialNumber)) + '-' + WordToHex(LoWord(VolumeSerialNumber));
end;
function InitializeSetup(): Boolean;
begin
MsgBox(FindVolumeSerial('c:\'), mbInformation, mb_Ok);
end;
Tested with Inno-setup version 5.2.3
In Unicode versions of Inno-Setup replace PChar with PAnsiChar
Since the InnoSetup doesn't support pointers you will have to create the external library for the call of the GetVolumeInformation function. The following code samples should work for all combinations of the Delphi and InnoSetup (from the Unicode support point of view).
Here's the Delphi library code:
library VolumeInformation;
uses
Types, Classes, SysUtils, Windows;
var
SerialNumber: AnsiString;
function GetVolumeSerial(Drive: PAnsiChar): PAnsiChar; stdcall;
var
FileSystemFlags: DWORD;
VolumeSerialNumber: DWORD;
MaximumComponentLength: DWORD;
begin
SerialNumber := '';
GetVolumeInformationA(Drive, nil, 0, #VolumeSerialNumber,
MaximumComponentLength, FileSystemFlags, nil, 0);
SerialNumber := IntToHex(HiWord(VolumeSerialNumber), 4) + ' - ' +
IntToHex(LoWord(VolumeSerialNumber), 4);
Result := PAnsiChar(SerialNumber);
end;
exports
GetVolumeSerial;
end.
And here's the InnoSetup code:
[Files]
Source: "VolumeInformation.dll"; Flags: dontcopy
[Code]
function GetVolumeSerial(Drive: PAnsiChar): PAnsiChar;
external 'GetVolumeSerial#files:VolumeInformation.dll stdcall setuponly';
procedure ButtonOnClick(Sender: TObject);
var
S: string;
begin
S := GetVolumeSerial('c:\');
MsgBox(S, mbInformation, mb_Ok);
end;

Resources