Problem:
MS Remote Desktop is installed on a MAC. You've got a server set up to provision Remote Apps. You can connect to the server via the 'Desktops' tab but trying to access the Remote Apps is a different story. You can enter the resource feed,
https://192.168.0.100/RDWeb/Feed/webfeed.aspx
and you can enter your username/password details to make the app appear well enough in the App list....but when you come to open it, it kicks back with a 'Unable to connect to remote PC. Please Verify Remote is enabled, the remote PC is turned on and Available on the network, and then try again' error.
This is a little confusing since you've been able to talk to the server to get the app to show but no, apparently, you can't run the app because the server has vanished.
Fix:
As counter intuitive as it may seem, the fix is to use the FQDN and edit the host file on the mac to resolve the fqdn to the server's ip address.
So on the client mac edit the host file (open the Terminal and enter 'sudo nano /etc/hosts') and add in an entry for your server and the ip address. Then change the resource feed url to use the FQDN:
https://myserver.mydomain.local/RDWeb/Feed/webfeed.aspx
Try opening the app now and you should find it works.
Wednesday, 10 July 2019
Wednesday, 12 September 2018
Delphi - Add an icon to a Node in TTreeView
1. Add your tree view to the form.
2. Add an TImageList to the form.
3. Double click on the ImageList component and add some images in.
4. Go to the Properties of the TreeView > Drop down the 'Images' property and select the name of the ImageList you've added.
5. Now in your code, where you're populating the treeview, you can add in code to set an icon/image to each node by referncing the image index:
//This will set the image of the node when resting
MyNode.ImageIndex := 0;
//This will set the image of node when selected
MyNode.SelectedIndex := 0;
The index number refers to the image in the IMageList. This is zero based so the first image would be 0, the second would 1 and so on...
Monday, 30 July 2018
Delphi - Sort an Object List by Property
Below is a quick example of how to use the .Sort function. In this case i have two objects declared in the Type seciton. On form create i am creating an instance of TPersons, then creating a number of dummy TPersons and adding them to my 'Persons'. Then behind a button click i am sorting the order of the Persons using the following code:
Persons.Sort(TComparer<TPerson>.Construct(
function (const L,R: TPerson): integer
begin
if L.Name > R.Name then
Result := 1
else if L.Name < R.Name then
Result := -1
else
Result := 0;
end
));
end;
To recreate this simple example, drop a memo and a button on a form. The make your code look like this:
unit Unit2;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
FMX.Controls.Presentation, FMX.StdCtrls, Generics.Collections, FMX.ScrollBox,
FMX.Memo, Generics.Defaults;
type
TForm2 = class(TForm)
Button1: TButton;
Button2: TButton;
Memo1: TMemo;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
TPerson = class(TObject)
Name: string;
Age: integer;
end;
TPersons = class(TObjectList<TPerson>)
end;
var
Form2: TForm2;
implementation
{$R *.fmx}
var
Persons: TPersons;
procedure TForm2.Button1Click(Sender: TObject);
var
Person: TPerson;
I: Integer;
begin
for Person in Persons do
begin
Persons.Sort(TComparer<TPerson>.Construct(
function (const L,R: TPerson): integer
begin
if L.Name > R.Name then
Result := 1
else if L.Name < R.Name then
Result := -1
else
Result := 0;
end
));
end;
for I := 0 to Persons.Count -1 do
begin
Memo1.Lines.Add(Persons[I].Name);
end;
end;
procedure TForm2.FormCreate(Sender: TObject);
var
Person: TPerson;
I: Integer;
begin
Persons := TPersons.Create(true);
Person := TPerson.Create;
Person.Name := 'John';
Person.Age := 34;
Persons.Add(Person);
Person := TPerson.Create;
Person.Name := 'James';
Person.Age := 31;
Persons.Add(Person);
Person := TPerson.Create;
Person.Name := 'Sally';
Person.Age := 21;
Persons.Add(Person);
end;
procedure TForm2.FormDestroy(Sender: TObject);
begin
Persons.Free;
end;
end.
Monday, 23 July 2018
Delphi FMX/Firemonkey - Fill a Rect/RoundRect/Ellipse with a Image/Bitmap
Here is a simple example of how to fill a given shape (TRectangle, TRoundRect, TEllipse etc) with the bitmap which belongs to an image. In this example i have created a new project, dropped a button and an RoundRect onto the form. On the Button Click i have the following code:
procedure TForm1.Button1Click(Sender: TObject);
var
Image: TImage;
begin
Image := TImage.Create(self);
Image.Bitmap.LoadFromFile('C:\Temp\Test.jpg');
RoundRect1.Fill.Kind := TbrushKind.Bitmap;
RoundRect1.Fill.Bitmap.WrapMode := TWrapMode.TileStretch;
RoundRect1.Fill.Bitmap.Bitmap := Image.Bitmap;
end;
This will create a new instance of a TImage. Load my Test.jpg file into its Bitmap property. Then set the Image to fill the space in the RoundRect.
procedure TForm1.Button1Click(Sender: TObject);
var
Image: TImage;
begin
Image := TImage.Create(self);
Image.Bitmap.LoadFromFile('C:\Temp\Test.jpg');
RoundRect1.Fill.Kind := TbrushKind.Bitmap;
RoundRect1.Fill.Bitmap.WrapMode := TWrapMode.TileStretch;
RoundRect1.Fill.Bitmap.Bitmap := Image.Bitmap;
end;
This will create a new instance of a TImage. Load my Test.jpg file into its Bitmap property. Then set the Image to fill the space in the RoundRect.
Thursday, 19 July 2018
Delphi - Set Font Property of a Component in Firemonkey/FMX
In order to set the font property of a component in FMX there are two ways you can do it:
1) In design time. By dropping a component onto the form and then changing its properties in the Object Inspector you can alter the properties of the font (font fmaily, size, color etc).
2) At run time. If, for example, you have a project which drops a series of labels onto a form when a button is clicked then you'll need to handle the changing of the font in your code.
Option 1 is pretty straight forward but it's worth noting that if you make this change, you can view the effect this has had by saving your project and then opening up the .fmx file in notedpad and looking to see what has changed. In my project, i added a label to my form and changed the Text Settings > Font Color to be 'crimson'. In my .fmx file i can see that there are now two new lines:
object Label1: TLabel
Position.X = 120.000000000000000000
Position.Y = 352.000000000000000000
TextSettings.FontColor = claCrimson
StyledSettings = [Family, Size, Style]
Text = 'Label1'
end
This shows us what the impact was of changing the font color. The first change is to be expected since the property we changed was the FontColor. The second change is important, however, since it shows us what other change delphi made under the covers - namely that delphi altered the StyledSettings. The styled settings tell delphi whether to pull down the projects style settings (i.e. those which may be applied through a stylebook) for a given setting. Thus if you go back to design time and drop down the StyledSettings option, you'll see that 'FontColor' is currently unchecked. If you check the box against it, the font in the label will cease to be red.
Thus, if you're creating new components at run time and need to alter some property of the font style, you'll need to include two lines - one to set the font setting and one to uncheck the relevant setting in StyledSettings:
MyLabel.TextSettings.FontColor := TAlphaColor($FF009900);
MyLabel.StyledSettings := [TStyledSetting.Family, TStyledSetting.Size, TStyledSetting.Style];
1) In design time. By dropping a component onto the form and then changing its properties in the Object Inspector you can alter the properties of the font (font fmaily, size, color etc).
2) At run time. If, for example, you have a project which drops a series of labels onto a form when a button is clicked then you'll need to handle the changing of the font in your code.
Option 1 is pretty straight forward but it's worth noting that if you make this change, you can view the effect this has had by saving your project and then opening up the .fmx file in notedpad and looking to see what has changed. In my project, i added a label to my form and changed the Text Settings > Font Color to be 'crimson'. In my .fmx file i can see that there are now two new lines:
object Label1: TLabel
Position.X = 120.000000000000000000
Position.Y = 352.000000000000000000
TextSettings.FontColor = claCrimson
StyledSettings = [Family, Size, Style]
Text = 'Label1'
end
This shows us what the impact was of changing the font color. The first change is to be expected since the property we changed was the FontColor. The second change is important, however, since it shows us what other change delphi made under the covers - namely that delphi altered the StyledSettings. The styled settings tell delphi whether to pull down the projects style settings (i.e. those which may be applied through a stylebook) for a given setting. Thus if you go back to design time and drop down the StyledSettings option, you'll see that 'FontColor' is currently unchecked. If you check the box against it, the font in the label will cease to be red.
Thus, if you're creating new components at run time and need to alter some property of the font style, you'll need to include two lines - one to set the font setting and one to uncheck the relevant setting in StyledSettings:
MyLabel.TextSettings.FontColor := TAlphaColor($FF009900);
MyLabel.StyledSettings := [TStyledSetting.Family, TStyledSetting.Size, TStyledSetting.Style];
Monday, 9 July 2018
Delphi - Load Image From Project Resource (FMX) - Simple Example
For this example i have a created a new FMX (firemonkey) form. I have added a button and an image onto the. I have then gone to Project > Resources and Images, and loaded in a bitmap image. I have set:
Resource Identifier: 'Bitmap_1'.
Resource Type: 'RCDATA'
Back on my form i have double clicked on the button and behind the button click put the code to instantiate a resource stream, load the image into it, assign it to a bitmap and then set it to be the image on the form.
unit Unit2;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Objects,
FMX.Controls.Presentation, FMX.StdCtrls;
type
TForm2 = class(TForm)
Image1: TImage;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form2: TForm2;
implementation
{$R *.fmx}
procedure TForm2.Button1Click(Sender: TObject);
var
B: TBitmap;
RS: TResourceStream;
begin
RS := TResourceStream.Create(HInstance, 'Bitmap_1', RT_RCDATA);
try
B := TBitmap.Create;
B.LoadFromStream(RS);
Image1.Bitmap := B;
finally
RS.Free;
end;
end;
end.
Resource Identifier: 'Bitmap_1'.
Resource Type: 'RCDATA'
Back on my form i have double clicked on the button and behind the button click put the code to instantiate a resource stream, load the image into it, assign it to a bitmap and then set it to be the image on the form.
unit Unit2;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Objects,
FMX.Controls.Presentation, FMX.StdCtrls;
type
TForm2 = class(TForm)
Image1: TImage;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form2: TForm2;
implementation
{$R *.fmx}
procedure TForm2.Button1Click(Sender: TObject);
var
B: TBitmap;
RS: TResourceStream;
begin
RS := TResourceStream.Create(HInstance, 'Bitmap_1', RT_RCDATA);
try
B := TBitmap.Create;
B.LoadFromStream(RS);
Image1.Bitmap := B;
finally
RS.Free;
end;
end;
end.
Thursday, 26 April 2018
Delphi - TFileStream - Simple Example
TFileStream can be handy for looking at a file without having to actually load it into memory since it just provides a more efficient way to view it on disk. Below is a very simple example illustrating how to locate a character in a filestream:
procedure TForm1.Button1Click(Sender: TObject);
var
FS: TFileStream;
X: char;
begin
FS := TFileStream.Create('C:\Temp\Example.txt', fmOpenRead);
try
FS.Position := 0;
FS.Read(X,2);
ShowMessage(X);
finally
FS.Free;
end;
end;
This will create a filestream based on the information fed to the constructor, i.e. the file and the mode of operation.
It will then set the position of the filestream to 0, i.e. what is my start point in the stream (it's 0 by default but if you wanted to alter your start point, this is how you'd do it).
It will then perform a Read on the string. It will start at the current position (in this case 0) and then read the number of bytes specified (in this case 2) and it will store these bytes in memory at a given location (in this case X).
It will then show a message of the first character in the text file.
Finally we free the filestream which ensures there is no memory leak.
NB, it is important to declare the X var at the start, since this will ensure that memory space is created. This space will then be used by FS.Read later to store data extracted from the filestream. In this example i have set it to be a char, since a char is 2 bytes of memory and i was just extracting the first two bytes of the stream but you could set it to something different so long as that something requires the same (or greater) memory than the amount of information you plan to extract from the filestream.
procedure TForm1.Button1Click(Sender: TObject);
var
FS: TFileStream;
X: char;
begin
FS := TFileStream.Create('C:\Temp\Example.txt', fmOpenRead);
try
FS.Position := 0;
FS.Read(X,2);
ShowMessage(X);
finally
FS.Free;
end;
end;
This will create a filestream based on the information fed to the constructor, i.e. the file and the mode of operation.
It will then set the position of the filestream to 0, i.e. what is my start point in the stream (it's 0 by default but if you wanted to alter your start point, this is how you'd do it).
It will then perform a Read on the string. It will start at the current position (in this case 0) and then read the number of bytes specified (in this case 2) and it will store these bytes in memory at a given location (in this case X).
It will then show a message of the first character in the text file.
Finally we free the filestream which ensures there is no memory leak.
NB, it is important to declare the X var at the start, since this will ensure that memory space is created. This space will then be used by FS.Read later to store data extracted from the filestream. In this example i have set it to be a char, since a char is 2 bytes of memory and i was just extracting the first two bytes of the stream but you could set it to something different so long as that something requires the same (or greater) memory than the amount of information you plan to extract from the filestream.
Wednesday, 26 July 2017
Windows Update Cleanup missing from Disk Cleanup - Windows 2008R2
Background:
Your server is full, or at least one disk is. You've tried the usual things:
Finally you check the Windows Component Store (C:\Windows\WinSXS) and find it's huge. Thus, you'll need to clear it down but don't start trying to manually delete stuff since a lot of these files are used by the OS.
To clear up this folder in Win2012 onwards, you can just use Disk Cleanup and tick the Windows Update Cleanup box but for 2008R2 you'll need to install a patch to add in the Windows Update Cleanup Option.
Install KB2852386 - this gives extra functionality to the Disk Cleanup wizard which includes the ability to remove all old Windows Update files (i.e. a good portion of the WinSXS folder).
Problem:
In spite of having installed the patch, you open disk cleanup only to find Windows Update Cleanup is not appearing on the Disk Cleanup list. Sad times.
Solution:
To get round this, open up an elevated CMD prompt and use the Cleanup Manager via this code:
and your custom clean job will tick over.
You can even save the cleanup job to your desktop or stick it in a scheduled task with the following cmd line:
Your server is full, or at least one disk is. You've tried the usual things:
- Sift through the *.tmp files
- Clear out any history/downloWindows ads/cookies etc from your browser
- Save & Clear the main logs (system, applicaiton etc) in Event Viewer
Finally you check the Windows Component Store (C:\Windows\WinSXS) and find it's huge. Thus, you'll need to clear it down but don't start trying to manually delete stuff since a lot of these files are used by the OS.
To clear up this folder in Win2012 onwards, you can just use Disk Cleanup and tick the Windows Update Cleanup box but for 2008R2 you'll need to install a patch to add in the Windows Update Cleanup Option.
Install KB2852386 - this gives extra functionality to the Disk Cleanup wizard which includes the ability to remove all old Windows Update files (i.e. a good portion of the WinSXS folder).
Problem:
In spite of having installed the patch, you open disk cleanup only to find Windows Update Cleanup is not appearing on the Disk Cleanup list. Sad times.
Solution:
To get round this, open up an elevated CMD prompt and use the Cleanup Manager via this code:
Cleanmgr /sageset:1
(NB you can choose any number between 1 and 65355).
You'll now get a pop up which allows you to select all the things you want to clean for this iteration of CleanMgr.
Click OK to save it.
Then in the cmd prompt enter:Cleanmgr /sagerun:1
and your custom clean job will tick over.
You can even save the cleanup job to your desktop or stick it in a scheduled task with the following cmd line:
%systemroot%\system32\cmd.exe /c Cleanmgr /sagerun:XXXXX
Tuesday, 11 July 2017
JQuery - Alter Value in Input Without Using Class or ID
In this example we have the following html code:
<!DOCTYPE html>
<html>
<body>
<h1>Please Give Us Money</h1>
<p>Donate Below</p>
<input name="donation" value="0.00" maxlength="6" size="3" type="text">
</body>
</html>
Because the input doesn't have a class or id, we have to locate our target by making use of some of the informaiton we do know. In this case, we will use the 'name' of the input. The following code will change the 'value' from 0.00 to 3.00 for any input on the page which has a 'name' of 'donation':
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script>
$(document).ready(function(){
$('input[name="donation"]').attr('value', '3.00');
});
</script>
If the input did have an id (or class, although id is more appropriate) this would be a lot simpler. The HTML line would look like this:
<input id='donate' name="donation" value="0.00" maxlength="6" size="3" type="text">
and the JQuery would look like this:
$('#donate').attr('value', '3.00');
There are, no doubt, many other ways to achieve this but this is the way i found worked best for me.
<!DOCTYPE html>
<html>
<body>
<h1>Please Give Us Money</h1>
<p>Donate Below</p>
<input name="donation" value="0.00" maxlength="6" size="3" type="text">
</body>
</html>
Because the input doesn't have a class or id, we have to locate our target by making use of some of the informaiton we do know. In this case, we will use the 'name' of the input. The following code will change the 'value' from 0.00 to 3.00 for any input on the page which has a 'name' of 'donation':
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script>
$(document).ready(function(){
$('input[name="donation"]').attr('value', '3.00');
});
</script>
If the input did have an id (or class, although id is more appropriate) this would be a lot simpler. The HTML line would look like this:
<input id='donate' name="donation" value="0.00" maxlength="6" size="3" type="text">
and the JQuery would look like this:
$('#donate').attr('value', '3.00');
There are, no doubt, many other ways to achieve this but this is the way i found worked best for me.
Wednesday, 17 August 2016
Ordering/Ranking Multiple IP Addresses on the Same NIC
Problem:
Your add a second IP Address to the network card on your server. Suddenly things which involve the outbound connection are either misbehaving or not working at all (e.g. RDP, telnet).
Cause:
After 2008, Windows Server started to assign its ranking of IP Addresses based on whichever has the lowest numerical value. The order the IP Addresses were added onto the NIC no longer matters, so if you first added 182.168.1.20 and then added 192.168.1.10 you'd find that any outbound connections were made from the x.x.x.10 address.
You can confirm this by viewing the ranking of the IP Addresses. Open an elevated command prompt and type in:
netsh int ipv4 show ipaddresses level=verbose
Fix:
You must manually remove the new ip address and then add the new ip address back onto the NIC using
netsh int ipv4 add address "Ethernet" 192.168.1.10 SkipAsSource=True
Thus the new ip address will be added to the NIC but it will not take precidence over the old IP Address, even though it is numerically lower.
Your add a second IP Address to the network card on your server. Suddenly things which involve the outbound connection are either misbehaving or not working at all (e.g. RDP, telnet).
Cause:
After 2008, Windows Server started to assign its ranking of IP Addresses based on whichever has the lowest numerical value. The order the IP Addresses were added onto the NIC no longer matters, so if you first added 182.168.1.20 and then added 192.168.1.10 you'd find that any outbound connections were made from the x.x.x.10 address.
You can confirm this by viewing the ranking of the IP Addresses. Open an elevated command prompt and type in:
netsh int ipv4 show ipaddresses level=verbose
Fix:
You must manually remove the new ip address and then add the new ip address back onto the NIC using
netsh int ipv4 add address "Ethernet" 192.168.1.10 SkipAsSource=True
Thus the new ip address will be added to the NIC but it will not take precidence over the old IP Address, even though it is numerically lower.
Wednesday, 18 May 2016
Virtual Box - Drag and Drop/Copy and Paste Not Working
Problem:
Even though you've installed the Guest Additions software and enabled 'Bi-directional' drag and drop and copy and paste, you still can't move stuff from your host machine onto the Virtual Machine.
Fix:
To make this long term fix simply create a shortcut to the VBoxTray.exe and move it to your Startup folder.
Even though you've installed the Guest Additions software and enabled 'Bi-directional' drag and drop and copy and paste, you still can't move stuff from your host machine onto the Virtual Machine.
Fix:
Open up Task Manager on your VM, kill the Virtual Box Guest Additions Tray Application. Then, still in Task Manager, go to File > Run New Task > Browse to
C:\Program Files\Oracle\VirtualBox Guest Additions and choose VBoxTray.exe. Suddenly you should find you can copy and paste stuff.
To make this long term fix simply create a shortcut to the VBoxTray.exe and move it to your Startup folder.
Thursday, 31 March 2016
Daylight Savings - "System time synchronized with the hardware clock" - CMOS Issue
Problem:
After Daylight Savings has happened, you may find your HP server resolutely refuses to update to the correct time. Even though manually syncing the time with the Internet Time works, after a short while the time will drop an hour. You will then see this message in the System event log:
The system time has changed to
2016-03-29T09:13:28.500000000Z from 2016-03-29T10:13:27.986215700Z.
Change Reason: System time
synchronized with the hardware clock.
This tells you that the hardware clock (CMOS) is still an hour behind and that for some reason, Windows can't update it. As a result, every time you correct the time, it will fall back to the pre-Daylight Savings time.
Cause:
As it turns out the this is a hardware issue, which effects:
- HP ProLiant DL580 Gen8
- HP ProLiant BL460c Gen9
- HP ProLiant DL160 Gen9
- HP ProLiant DL180 Gen9
- HP ProLiant DL360 Gen9
- HP ProLiant DL380 Gen9
- HP ProLiant ML350 Gen9
- HP ProLiant XL230a Gen9
h20564.www2.hpe. com/hpsc/doc/public/display?docId=emr_na-c04557232&lang=en-us&cc=us
Fix:
The fix was to make the following registry change then reboot the server:
"Create a new DWORD sized Microsoft Windows registry setting named RealTimeIsUniversal under HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\TimeZoneInformation\ and set the value to '1'. This option will cause the Windows operating system to treat the Real Time Clock time as UTC rather than local time. "
Subscribe to:
Posts (Atom)