How to declare an object in the "Mastering delphi" book - delphi

Im learning delphi through books and am encountering a problem in this chapter: http://etutorials.org/Programming/mastering+delphi+7/Part+IV+Delphi+the+Internet+and+a+.NET+Preview/Chapter+19+Internet+Programming+Sockets+and+Indy/Building+Socket+Applications/#toc
It is this peace of code that gives me trouble because i dont know where to write it.
object IdTCPServer1: TIdTCPServer
CommandHandlers = <
item
Command = 'test'
Name = 'TIdCommandHandler0'
ParseParams = False
ReplyNormal.NumericCode = 100
ReplyNormal.Text.Strings = (
'Hello from your Indy Server')
ReplyNormal.TextCode = '100'
end

That is part of a DFM file of a form with a non-visual component called TIdTCPServer on it. Just place such a component on your form and use the property editor to set the properties to the given values. For example, you have to add a command handler (using the CommandHandlers property) and set its Command property to "test".

That is part of the DFM file, which you don't edit directly. I just placed a TIdTCPServer on a form and the DFM shows:
object IdTCPServer1: TIdTCPServer
Bindings = <>
DefaultPort = 0
Left = 80
Top = 112
end
You can see this for yourself if you right click on your form and choose 'View as Text' (or if you inspect the .DFM files in an editor if you have your configuration set to save them as text.
When you start filling in more (non-default) properties of the TIdTCPServer, Delphi will store these in the DFM as well. I don't see a CommandHandlers property in my Delphi version (XE2, Indy 10.5.8.0), but yours has one (in the example).
[Edited to add] I see from your comment on another answer that you do not have a CommandHandlers property for TIdTCPServer either, this may indicate that the book author used a different Indy version than you do. You can see your version by right-clicking on any Indy component on the form.
CommandHandlers are indeed old. Googling "tidtcpserver commandhandlers" leads to e.g. "The CommandHandlers collection was moved to a new TIdCmdTCPServer component in Indy 10." That makes me suspect you have Indy 10 and the book references 9. You'll have to find Indy 10 examples for what you want to do. That should not be too difficult.

Related

Delphi TurboPower Async Professional Data Packet Access Violation…

I use windows 7, 64-bit SP1, and TP Async V4.07 and have the following problem:
I have two Com ports, Com11, and Com18.
I add the following components to my form:
I open a Com port on ApdComPort2 (Com18) and it works without a problem. The ApdDataPacket2 detects the packet terminator and the result displayed is what is expected. Both Com11 and Com18 work fine.
Now if I open another Com port (Com11) with ApdComPort1 I get an Access violation:
The code that generates the error is this in the AdPacket module:
procedure TApdDataPacketManager.EnablePackets;
var
i : integer;
begin
for i := 0 to pred(PacketList.Count) do
with TApdDataPacket(PacketList[i]) do
if Enabled then
Enable;
end;
It is the PacketList.Count that seems to be the problem when it iterates through the list but I can’t catch why:
Note that ApdComPort2 works without problem with both Com11 and Com18.
If I remove the Apd2 components then Apd1 works as expected. The problems surface when I try to use two (or more) Apd components at the same time.
Does anybody have a suggestion or can recommend a component that works with more than one serial port simultaneously?
Some notes about the Turbo Power Async Professional components:
When using the Async components it is very important on how you add the components to the form. If you don’t does it in the right order and in the correct way it will not work if you use more than one serial port. You will actually get an access violation. For example, if you add the components below you have to do it in this way:
Add one ApdComPort to the form, it will become ApdComPort1
Now copy and paste this component to the form, it will become ApdComPort2
Add one ApdDataPacket component to the form, it will become ApdDataPacket1
Now copy and paste this component to the form, it will become ApdDataPacket2
Add one ApdSLController component to the form, it will become ApdSLController1
Now copy and paste this component to the form, it will become ApdSLController2
When doing it, as described above, it works to use two serial ports with ApdDatapacket. Now I don’t get any getting Access violations. I have tested it up to 4 ports and it works as well.

Access violation when creating ActiveX control after upgrading to C++Builder 11

The following code creates an ActiveX component on a hidden form. It works well with C++Builder 10.4, but crashes when compiled with C++Builder 11.0.
container = new TForm((TComponent*)NULL);
container->Visible = false;
softlock = new TCryptoLicense(container); // <= A.V.
softlock->Parent = container;
The Access Violation occurs in the constructor of TControl after CreateTouchManager, when it uses FTouchManager. I have already tried the following things that did not help:
make the form visible
add an Owner to the Form constructor
call HandleNeeded on the container
create it delayed, not in startup of application
Dropping the component unto a form in a new application caused the same exception to occur at design time.
Reimporting the ActiveX control into a new package fixed the problem. Maybe some data from CB10 and CB11 got mixed up.

TSaveDialog Options ofAllowMultiSelect doesn't work properly on a W10 system

I have an old application, untouched for a long time, built with C++ Builder 2009, that still works fine.
That is to say ..
Today I noticed some of the TSaveDialog->Options don't work as intended on my Windows 10 system. To make sure I'm not dreaming I tested the same application on an older Windows version (I tried XP) and there it worked perfectly fine as intended.
The TSaveDialog instance is setup at design time with Options: [ofHideReadOnly,ofAllowMultiSelect,ofEnableSizing]
I noticed today (on Windows 10) that ofAllowMultiSelect doesn't work anymore ?
Instead ofOverwritePrompt is (incorrectly) used !
In other words I cannot select two ore more files anymore and when I select a file that already exists I first get a 'Confirm Save As' dialog.
When I compile again on my Windows 10 system, using C++ Builder 2009, in debug mode and inspect Options, the debugger seems to (still) properly see ofHideReadOnly, ofAllowMultiSelect, ofEnableSizing, yet the problem persists. So it's not as if the values changed somehow ?
When I try at runtime:
SaveDialog->Options.Clear() ;
SaveDialog->Options << ofHideReadOnly << ofEnableSizing << ofAllowMultiSelect ;
the problem also persists !
When I remove ofAllowMultiSelect (at run time or at design time) 'Confirm Save As' is not shown anymore on an existing file (but I obviously also still can't select multiple files).
I'm flabbergasted by this to be honest ? Not sure what to do next ?
I have no option to test a more recent c++ version but I'm also having difficulties comprehending how the compiler could be responsible here.
Any guidance appreciated.
Delphi tag added because of VCL overlap between c++ Builder and Delphi
On Windows Vista and later, IF AND ONLY IF all of these conditions are met:
the global Dialogs::UseLatestCommonDialogs variable is true
and the TSaveDialog::Template property is NULL
and the TSaveDialog::OnIncludeItem, TSaveDialog::OnClose, and TSaveDialog::OnShow events have no handlers assigned
Then TSaveDialog will internally use the Win32 IFileSaveDialog interface, where the ofAllowMultiSelect option will be mapped to that dialog's FOS_ALLOWMULTISELECT option, which is NOT SUPPORTED by IFileSaveDialog, only by IFileOpenDialog, per the documentation:
FOS_ALLOWMULTISELECT
Enables the user to select multiple items in the open dialog. Note that when this flag is set, the IFileOpenDialog interface must be used to retrieve those items.
If the above 3 conditions are not satisfied, then TSaveDialog will internally use the Win32 GetSaveFileName() function instead, where the ofAllowMultiSelect option will be mapped to that dialog's OFN_ALLOWMULTISELECT option, which IS SUPPORTED by GetSaveFileName() 1.
That is why you are seeing behavioral differences when running your app on Windows XP vs Windows 10.
So, if you want the old TSaveDialog behavior on newer Windows versions, you need to make sure at least 1 of those 3 conditions is not satisfied. For instance, by setting UseLatestCommonDialogs=false before calling SaveDialog->Execute(), or by assigning an (empty) event handler to one of the OnIncludeItem/OnClose/OnShow events.
Or, you could simply call GetSaveFileName() directly, instead of using TSaveDialog at all.
1: However, just note that on Vista+, GetSaveFileName() is just a wrapper for IFileSaveDialog, and is provided only for backwards compatibility. So, you still might not get the exact behavior you want even if you did use GetSaveFileName() on Windows 10.
On a side note: this code does not work the way you think it does:
SaveDialog->Options.Clear();
SaveDialog->Options << ofHideReadOnly << ofEnableSizing << ofAllowMultiSelect;
The Options property is not actually updated! In both statements, the Options property is read from, returning a temporary TOpenOptions, which you are then modifying, but not assigning back to the Options property. IOW, the code is effectively doing the following:
TOpenOptions temp1 = SaveDialog->Options;
temp1.Clear();
TOpenOptions temp2 = SaveDialog->Options;
temp2 << ofHideReadOnly << ofEnableSizing << ofAllowMultiSelect;
So, to update the Options property correctly, use this instead:
SaveDialog->Options = TOpenOptions() << ofHideReadOnly << ofEnableSizing << ofAllowMultiSelect;

Calling SHGetSetSettings from Delphi XE returns nothing

What I try to do is to hide the desktopicons.
I have a hack that works but I want to do it the proper way, using SHGetSetSettings.
The thing is that after calling SHGetSetSettings, the record is filled with zeros!
procedure GetDesktopData;
var
lpss: tagSHELLSTATEW;
begin
ZeroMemory(#lpss, SizeOf(lpss));
SHGetSetSettings(lpss, SSF_HIDEICONS, FALSE); { TRUE to indicate that the contents of lpss should be used to set the Shell settings, FALSE to indicate that the Shell settings should be retrieved to lpss. }
end;
What am I doing wrong? Why the record was not filled with data?
I have Windows 7.
This question is similar to this one Calling SHGetSetSettings from Delphi, but not identical. That question discusses the structure for calling SHGetSetSettings from Delphi 2010. The function and the afferent structure is now present under Delphi xE (but still not working).
Solution provided by TLama.

Find out what process registered a global hotkey? (Windows API)

As far as I've been able to find out, Windows doesn't offer an API function to tell what application has registered a global hotkey (via RegisterHotkey). I can only find out that a hotkey is registered if RegisterHotkey returns false, but not who "owns" the hotkey.
In the absence of a direct API, could there be a roundabout way? Windows maintains the handle associated with each registred hotkey - it's a little maddening that there should be no way of getting at this information.
Example of something that likely wouldn't work: send (simulate) a registered hotkey, then intercept the hotkey message Windows will send to the process that registered it. First, I don't think intercepting the message would reveal the destination window handle. Second, even if it were possible, it would be a bad thing to do, since sending hotkeys would trigger all sorts of potentially unwanted activity from various programs.
It's nothing critical, but I've seen frequent requests for such functionality, and have myself been a victim of applications that register hotkeys without even disclosing it anywhere in the UI or docs.
(Working in Delphi, and no more than an apprentice at WinAPI, please be kind.)
One possible way is to use the Visual Studio tool Spy++.
Give this a try:
Run the tool (for me, it's at C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\Tools\spyxx_amd64.exe or you can download it). Note: there is spyxx.exe (32-bit version) and spyxx_amd64.exe (64-bit version) - if you don't see anything in 64-bit use the 32-bit version (ie.catches messages only in same architecture)
In the menu bar, select Spy -> Log messages... (or hit Ctrl + M)
Check All Windows in System in the Additional Windows frame
Switch to the Messages tab
Click the Clear All button
Select WM_HOTKEY in the listbox, or check Keyboard in Message Groups (if you're OK with more potential noise)
Click the OK button
Press the hotkey in question (Win + R, for example)
Select the WM_HOTKEY line in the Messages (All Windows) window, right click, and select Properties... in the context menu
In the Message Properties dialog, click the Window Handle link (this will be the handle for the window that received the message)
Click the Synchronize button on the Window Properties dialog. This will show the window in the main Spy++ window treeview (if it's windows itself or some popup application it shows nothing).
On the Window Properties dialog, select the Process tab
Click the Process ID link. This will show you the process (In my Win + R case: EXPLORER)
Your question piqued my interest, so I've done a bit of digging and while, unfortunately I don't have a proper answer for you, I thought I'd share what I have.
I found this example of creating keyboard hook (in Delphi) written in 1998, but is compilable in Delphi 2007 with a couple of tweaks.
It's a DLL with a call to SetWindowsHookEx that passes through a callback function, which can then intercept key strokes: In this case, it's tinkering with them for fun, changing left cursor to right, etc. A simple app then calls the DLL and reports back its results based on a TTimer event. If you're interested I can post the Delphi 2007 based code.
It's well documented and commented and you potentially could use it as a basis of working out where a key press is going. If you could get the handle of the application that sent the key strokes, you could track it back that way. With that handle you'd be able to get the information you need quite easily.
Other apps have tried determining hotkeys by going through their Shortcuts since they can contain a Shortcut key, which is just another term for hotkey. However most applications don't tend to set this property so it might not return much. If you are interested in that route, Delphi has access to IShellLink COM interface which you could use to load a shortcut up from and get its hotkey:
uses ShlObj, ComObj, ShellAPI, ActiveX, CommCtrl;
procedure GetShellLinkHotKey;
var
LinkFile : WideString;
SL: IShellLink;
PF: IPersistFile;
HotKey : Word;
HotKeyMod: Byte;
HotKeyText : string;
begin
LinkFile := 'C:\Temp\Temp.lnk';
OleCheck(CoCreateInstance(CLSID_ShellLink, nil, CLSCTX_INPROC_SERVER, IShellLink, SL));
// The IShellLink implementer must also support the IPersistFile
// interface. Get an interface pointer to it.
PF := SL as IPersistFile;
// Load file into IPersistFile object
OleCheck(PF.Load(PWideChar(LinkFile), STGM_READ));
// Resolve the link by calling the Resolve interface function.
OleCheck(SL.Resolve(0, SLR_ANY_MATCH or SLR_NO_UI));
// Get hotkey info
OleCheck(SL.GetHotKey(HotKey));
// Extract the HotKey and Modifier properties.
HotKeyText := '';
HotKeyMod := Hi(HotKey);
if (HotKeyMod and HOTKEYF_ALT) = HOTKEYF_ALT then
HotKeyText := 'ALT+';
if (HotKeyMod and HOTKEYF_CONTROL) = HOTKEYF_CONTROL then
HotKeyText := HotKeyText + 'CTRL+';
if (HotKeyMod and HOTKEYF_SHIFT) = HOTKEYF_SHIFT then
HotKeyText := HotKeyText + 'SHIFT+';
if (HotKeyMod and HOTKEYF_EXT) = HOTKEYF_EXT then
HotKeyText := HotKeyText + 'Extended+';
HotKeyText := HotKeyText + Char(Lo(HotKey));
if (HotKeyText = '') or (HotKeyText = #0) then
HotKeyText := 'None';
ShowMessage('Shortcut Key - ' + HotKeyText);
end;
If you've got access to Safari Books Online, there is a good section about working with shortcuts / shell links in the Borland Delphi 6 Developer's Guide by Steve Teixeira and Xavier Pacheco. My example above is a butchered version from there and this site.
Hope that helps!
After some research, it appears that you'd need to get access to the internal structure that MS uses to store the hotkeys. ReactOS has a clean room implementation that implements the GetHotKey call by iterating an internal list and extracting the hotkey that matches the parameters to the call.
Depending on how close ReactOS' implementation is to the MS implementation, you may be able to poke around in memory to find the structure, but that's over my head...
BOOL FASTCALL
GetHotKey (UINT fsModifiers,
UINT vk,
struct _ETHREAD **Thread,
HWND *hWnd,
int *id)
{
PHOT_KEY_ITEM HotKeyItem;
LIST_FOR_EACH(HotKeyItem, &gHotkeyList, HOT_KEY_ITEM, ListEntry)
{
if (HotKeyItem->fsModifiers == fsModifiers &&
HotKeyItem->vk == vk)
{
if (Thread != NULL)
*Thread = HotKeyItem->Thread;
if (hWnd != NULL)
*hWnd = HotKeyItem->hWnd;
if (id != NULL)
*id = HotKeyItem->id;
return TRUE;
}
}
return FALSE;
}
I presume this thread on sysinternals was asked by someone related to this question, but I thought I'd link to it anyway to keep the two together. The thread looks very intriguing, but I suspect that some deep dive spelunking would need to happen to figure this out without access to the MS internals.
Off the top of my head, you might try enumerating all windows with EnumWindows, then in the callback, send WM_GETHOTKEY to each window.
Edit: Apparrently I was wrong about that. MSDN has more information:
WM_HOTKEY is unrelated to the WM_GETHOTKEY and WM_SETHOTKEY hot keys. The WM_HOTKEY message is sent for generic hot keys while the WM_SETHOTKEY and WM_GETHOTKEY messages relate to window activation hot keys.
Note: Here is a program purporting to have the functionality you are looking for. You could try decompiling it.
Another thread mentions a global NT level keyboard hook:
Re-assign/override hotkey (Win + L) to lock windows
maybe you can get the handle of the process that called the hook that way, which you can then resolve to the process name
(disclaimer: I had it in my bookmarks, haven't really tried/tested)
I know you can intercept the stream of messages in any window within your own process - what we used to call subclassing in VB6. (Though I do not remember the function, perhaps SetWindowLong?) I am unsure if you can do this for windows outside your own process. But for the sake of this post lets assume you find a way to do that. Then you can simply intercept the messages for all top level windows, monitor for the WM_HOTKEY message. You wouldn't be able to know all the keys right off the bat, but as they were pressed you could easily figure out what application was using them. If you persisted your results to disk and reloaded each time your monitor application was run you could increase the performance of your application over time.
This doesn't exactly answer the part of the question that is about the Windows API, but it answers the part of the question that is about a list of global hotkeys and the applications that "own" them.
The free Hotkey Explorer at http://hkcmdr.anymania.com/ shows a list of all global hotkeys and the applications that own them. This just has helped me figure out why an application-specific shortcut key stopped working and how to fix it (by reconfiguring the registered global hotkey in the app that had it registered), within a few seconds.

Resources