I've used Delphi for some time, but I am trying some COM programming and having trouble. I apologize if this is a NewBie issue, but after searching an trying lots of things I have not been able to get or set the properties of an RDPEncom RDPSession object. The code (including several naive attemps) is below. If I remove the line attempting to read properties, remaining code works fine.
How can I get and Set the PortID property of RDPSession.Properties ?
uses rdpencomapi_TLB; // from JWAPI
...
myRDPSession := CoRDPSession.Create();
if VarIsNull(myRDPSession) then
begin
application.MessageBox('MsRdpSession creation failed.', 'Error');
Result := False;
Exit;
end;
try
didShare := myRDPSession.Open;
except
ShowMessage('Unable to share desktop !');
Exit;
end;
theProperty := 'PortID';
ActiveXProp := myRDPSession.Properties;
//lValues := ActiveXProp.Property_(theProperty); // method not supported
//lValues := ActiveXProp.Property(theProperty); // member not found
myRDPSession.Properties.GetProperty(lValues, myRDPSession.Properties.Property, theProperty);
{
ALL RETURN INVALID NUMBER OF PARAMETERS..
ActiveXProp.GetProperty(lValues, ActiveXProp.Property, 'PortID');
ActiveXProp.Property.GetProperty(ActiveXProp.Property, lValues, 'PortID');
ActiveXProp.Property.GetProperty(lValues, ActiveXProp, 'PortID');
ActiveXProp.Property.Get_Prop_('PortID', ActiveXProp);
ActiveXProp.Property.SetProperty('PortID', ActiveXProp);
ActiveXProp.Property.Set_Prop_('PortID', ActiveXProp);
}
ActiveXInvite := myRDPSession.Invitations.CreateInvitation('RemoteSupport', 'WePresent', '12345', 75);
...
Ken,
Your comment put me onto something.. I regenerated the TLB file from my own machine and found it did have a property that was not in the TLB I used originally (from Jedi Project). This one has a single Property called 'Property' that allowed me to do what I needed. Basically I was missing the COM interface point. I got it to work after updating the TLB this way (with no error checking yet):
// get properties interface
myRDPSessionProp := myRDPSession.Properties;
// set listening port
myRDPSessionProp.Property['PortID'] := 59000;
// set color depth
myRDPSession.colorDepth := 8;
didShare := myRDPSession.Open;
I am developing an application in Firemonkey (Delphi XE5) where I am using Fast report 4 for printing data. I am using TFrxUserDataSet to keep data and to print this, I am using MasterData band in fast report.
Now, I also need to print TBitamp with each row, so here the bitmap for each record will be different.
Does any body has any idea how can I do this?
Нou can load an external image file into a picture control in your report. I'm doing this with a script that is part of the report itself using the OnBeforePrint event as follows:
PROCEDURE Data2OnBeforePrint(Sender: TfrxComponent);
VAR
lFN : STRING;
lFP : STRING;
BEGIN
// Use the filename as found in the Media dataset fields
lFP := Trim(< Media."ImagePath">); // Images folder below Image Root Path
lFN := Trim(< Media."FileName1">); // Actual Image File Name
WITH Picture2 DO BEGIN
// NB: There is no checking in this example, it may be useful to do a
// couple of checks before trying to load the image, especially if
// the data is user entered
LoadFromFile(ImageRootPath + IncludeTrailingSlash(lFP) + lFN);
// Do whatever manipulations you want to with the loaded image...
AutoSize := False;
Width := 1620;
Height := 1080;
Top := 0;
Left := (1920 - Width) / 2;
HightQuality := True; // Note the typo in the property name... HighQuality?
KeepAspectRatio := True;
Transparent := True;
Stretched := NOT Picture3.AutoSize;
END;
END;
Note that I have added a few user functions like ImageRootPath IncludeTrailingSlash() to make the script easier. You could do similar to check for a valid file prior to attempting to load to avoid exceptions.
My devt environment is Delphi XE5 with FastReport FMX and it works just fine. I am in the midst of moving to XE6 and FR FMX 2, but am pretty sure this will work fine.
I am migrating the code from Delphi 7 to XE2 one of the Graphical module.
we are using TRect variable , the old code is working in Delphi 7 without issue
Ex:
Var
Beold : TRect
begin
Beold.left := Beold.right;
end.
while porting the code to new XE2 we are facing the issue
E0264 : Left side cannot be assigned to
Can you please explain what is the changes in XE2 TRect and D7, how we can assign the valuse
The code you posted compiles and runs fine in a quick Delphi test app, so it's not your real code.
I'd suspect what you've hit is a change in the with statement when it's related to using properties, however. There was a bug in previous versions of Delphi that existed for many years that was finally fixed recently. IIRC, it was first mentioned in a note in the README.HTML file for D2010. It's been added to the documentation in XE2 (not as a behavior change, but the new behavior is documented). The documentation is located here at the docwiki.
(Additional info: It must have been 2010 where it changed; Marco Cantù's Delphi 2010 Handbook mentions it on page 111 as "The With Statement Now Preserves Read-Only Properties" which describes this behavior and the solution I indicated below.)
Instead of accessing the property of a class directly using a with statement, you now need to declare a local variable, and read and write the whole thing directly (error handling omitted for clarity - yes, I know there should be a try..finally block to free the bitmap).
var
R: TRect;
Bmp: TBitmap;
begin
Bmp := TBitmap.Create;
Bmp.Width := 100;
Bmp.Height := 100;
R := Bmp.Canvas.ClipRect;
{ This block will not compile, with the `Left side cannot be assigned to` error
with Bmp.Canvas.ClipRect do
begin
Left := 100;
Right := 100;
end;
}
// The next block compiles fine, because of the local variable being used instead
R := Bmp.Canvas.ClipRect;
with R do
begin
Left := 100;
Right := 100;
end;
Bmp.Canvas.ClipRect := R;
// Do other stuff with bitmap, and free it when you're done.
end.
turns out, using
with (Bmp.Canvas.ClipRect) do
begin
Bottom := 100;
end;
throws error: [Left side cannot be assigned to]
Yet,
with Bmp.Canvas.ClipRect do
begin
Bottom := 100;
end;
does not.
Delphi 10.3.3 is just as finicky about parenthesis as the older versions.
How can i get the version of my running application?
i have been using GetFileVersionInfo(ParamStr(0), ...):
filename := PChar(ExtractShortPathName(ParamStr(0)));
//Get the number of bytes he have to allocate for the file information structure
dwInfoLength := GetFileVersionInfoSize(lptstrFilename, {var}dwHandle);
//Get version info
GetMem(pInfoData, dwInfoLength);
GetFileVersionInfo(lptstrFilename, dwHandle, dwInfoLength, pInfoData);
//Set what information we want to extract from pInfoData
lpSubBlock := PChar(Chr(92)+Chr(0));
//Extract the desired data from pInfoData into the FileInformation structure
VerQueryValue(pInfoData, lpSubBlock, PFileInformation, LengthOfReturned);
The problem with this technique is that it requires the Windows loader to load the image before the resources can be read. i build my applications with the IMAGE_FILE_NET_RUN_FROM_SWAP image flag (in order to avoid in-page exceptions on a fiddly network).
This causes the Windows loader to load the entire image across the network again, rather than just looking at "me". Since i check, and save, my own version at startup, a 6 second application startup turns into a 10 second application startup.
How can i read the version of me, my running application?
i would assume Windows has no API to read the version of a running process, only the file that i loaded from (and if the file no longer exists, then it cannot read any version info).
But i also assume that it might be possible to read version resources out of my processes own memory (without being a member of the Administrators or Debuggers group of course).
Can i read the version of my process?
Associated Bonus Question: How can i load PE Image resources from me rather than across the network?
Found it, right here on Stackoverflow:
How to determine Delphi Application Version
i already knew how to determine an application version, but #StijnSanders suggested the "better" way, for exactly the reasons i was hitting:
I most strongly recommend not to use GetFileVersion when you want to know the version of the executable that is currently running! I have two pretty good reasons to do this:
The executable may be unaccessible (disconnected drive/share), or changed (.exe renamed to .bak and replaced by a new .exe without the running process being stopped).
The version data you're trying to read has actually already been loaded into memory, and is available to you by loading this resource, which is always better than to perform extra (relatively slow) disk operations.
Which i adapted into:
function GetModuleVersion(Instance: THandle; out iMajor, iMinor, iRelease, iBuild: Integer): Boolean;
var
fileInformation: PVSFIXEDFILEINFO;
verlen: Cardinal;
rs: TResourceStream;
m: TMemoryStream;
resource: HRSRC;
begin
//You said zero, but you mean "us"
if Instance = 0 then
Instance := HInstance;
//UPDATE: Workaround bug in Delphi if resource doesn't exist
resource := FindResource(Instance, 1, RT_VERSION);
if resource = 0 then
begin
iMajor := 0;
iMinor := 0;
iRelease := 0;
iBuild := 0;
Result := False;
Exit;
end;
m := TMemoryStream.Create;
try
rs := TResourceStream.CreateFromID(Instance, 1, RT_VERSION);
try
m.CopyFrom(rs, rs.Size);
finally
rs.Free;
end;
m.Position:=0;
if not VerQueryValue(m.Memory, '\', (*var*)Pointer(fileInformation), (*var*)verlen) then
begin
iMajor := 0;
iMinor := 0;
iRelease := 0;
iBuild := 0;
Exit;
end;
iMajor := fileInformation.dwFileVersionMS shr 16;
iMinor := fileInformation.dwFileVersionMS and $FFFF;
iRelease := fileInformation.dwFileVersionLS shr 16;
iBuild := fileInformation.dwFileVersionLS and $FFFF;
finally
m.Free;
end;
Result := True;
end;
Warning: The above code crashes sometimes due to a bug in Delphi:
rs := TResourceStream.CreateFromID(Instance, 1, RT_VERSION);
If there is no version information, Delphi tries to raise an exception:
procedure TResourceStream.Initialize(Instance: THandle; Name, ResType: PChar);
procedure Error;
begin
raise EResNotFound.CreateFmt(SResNotFound, [Name]);
end;
begin
HResInfo := FindResource(Instance, Name, ResType);
if HResInfo = 0 then Error;
...
end;
The bug, of course, is that PChar is not always a pointer to an ansi char. With non-named resources they are integer constants, cast to a PChar. In this case:
Name: PChar = PChar(1);
When Delphi tries to build the exception string, and dereferences the pointer 0x00000001 it triggers and access violation.
The fix is to manually call FindResource(Instance, 1, RT_VERSION) first:
var
...
resource: HRSRC;
begin
...
resource := FindResource(Instance, 1, RT_VERSION);
if (resource = 0)
begin
iMajor := 0;
iMinor := 0;
iRelease := 0;
iBuild := 0;
Result := False;
Exit;
end;
m := TMemoryStream.Create;
...
Note: Any code is released into the public domain. No attribution required.
You might want to try FindResource/LockResource API in order to access VERSIONINFO resource of your running module. MSDN article links an example in Examples section, and there is also a community comment with C++ sample code which does exactly this. This starts from already loaded module, not from file name (which is supposedly loaded separately with flag indicating "load resources only", and thus possibly ignoring the fact that image is already mapped into process).
Note that - per provided code snippet - you can find resource of your module and then reuse standard VerQueryValue API to continue resource parsing from there.
I suggest you to read the code JclFileUtils.pas, from JCL.
The "TJclFileVersionInfo" class has some overloaded constructors that allows work from file and from the module handle to get version information.
You can use the JCL class, or at least read it for check how it works in details.
Delphi 10.3.3 provides a reasonable method to read ProductVersion from running exe. Set this value in [Options] [ProductVersion] of project exe.
set variables as:
var
major, minor, build: Cardinal;
Version: String;
set code as:
// [GetProductVersion] uses 1st 3 values separated by decimal (.)
// as: major, minor, build. 4th optional parameter is ignored.
//
// Gui may display -- Major, Minor, Release, Build
// but reports as -- Major, Minor, Build
if GetProductVersion(Application.ExeName, major, minor, build) then
Version := 'v' + major.ToString() + '.' + minor.ToString()
+ ' Beta Build ' + build.ToString();
I've run into the following problem:
My Delphi7 program runs smoothly on most computers running WinXP/Vista/7 BUT on some older Windows XP installs (only a few) I'm getting the following problem:
I have a system image list, and I'm adding my own icons to a copy of the system image list. Upon adding my icons I get an "Invalid image size." EInvalidOperation error.
Here is the code in question:
function GetSystemLargeIconsList: TCustomImageList;
// This gets the system image list.
var
SysIL: HImageList;
SFI: TSHFileInfo;
MyImages: TCustomImageList;
begin
SysIL := SHGetFileInfo('', 0, SFI, SizeOf(SFI),
SHGFI_SYSICONINDEX or SHGFI_LARGEICON);
if SysIL <> 0 then begin
MyImages:=TCustomImageList.Create(nil);
// Assign the system list to the component
MyImages.Handle := SysIL;
// The following prevents the image list handle from being
// destroyed when the component is.
MyImages.ShareImages := TRUE;
Result:=MyImages;
end;
end;
var
DocumentImgList: TCustomImageList;
IconToAdd: TIcon;
begin
DocumentImgList:=GetSystemLargeIconsList;
Documents.LargeImages:=DocumentImgList;
Documents.SmallImages:=DocumentImgList;
IconToAdd:=TIcon.Create;
DocumentListIcons.GetIcon(0, IconToAdd);
DocumentImgList.AddIcon(IconToAdd); ----> this is the line of the exception
To make the problem worse, I'm using the TPngImageList component, but according to the code, it just seems to call the standard Delphi function:
if TObject(Self) is TPngImageList
then if Image = nil
...
else begin
Patch := FindMethodPatch('AddIcon');
if Patch <> nil
then begin
Patch.BeginInvokeOldMethod;
try
Result := TCustomImageList(Self).AddIcon(Image); ----> this is where the exception happens
finally
Patch.FinishInvokeOldMethod;
end;
end
else Result := -1;
end;
I've recently found out that on one of the computers that have this problem, either uxtheme.dll or explorer.exe has been patched with some Windows-skinning program.
So I suppose that somebody or a program is hacking the system image list in a way that is making my Delphi program crash.
Any ideas on how to fix this?
Thanks!
One thing you could try would be to load your icon into a separate tBitmap, then resize it before adding it into the image list.