-
Content Count
2633 -
Joined
-
Last visited
-
Days Won
110
Everything posted by Remy Lebeau
-
That's fine if you control both apps. But what if you want to use a hotkey that is used by another app that you don't control? Then you are SOL. This is why apps are supposed to pick unique hotkeys for themselves, or allow the user to configure the hotkeys (see the VCL's THotKey component and TextToShortCut() function).
-
If you are referring to the Win32 RegisterHotKey() function and WM_HOTKEY window message, then such hotkeys are system-wide and any given hotkey can only be registered for one window at a time. To use the same hotkey with multiple processes at the same time, you will have to resort to using a global keyboard hook and handle the keystrokes manually.
-
Yes, it does, and should. The logic to detect when data arrives should not block, but once data is detected then it does block until the complete message has been received. If you don't want it to block at all, then you need to maintain your own cache for the raw bytes, and then parse those bytes yourself after each read. var Cache: TMemoryStream; procedure TForm2.FormCreate(Sender: TObject); begin Cache := TMemoryStream.Create; end; procedure TForm2.FormDestroy(Sender: TObject); begin Cache.Free; end; procedure TForm2.Timer1Timer(Sender: TObject); begin Timer1.Enabled := False; try with IdTCPClient1 do begin if not Connected then Exit(); // read any data in if IOHandler.InputBufferIsEmpty then begin IOHandler.CheckForDataOnSource(0); IOHandler.CheckForDisconnect; if IOHandler.InputBufferIsEmpty then Exit(); end; Cache.Position := Cache.Size; IOHandler.InputBuffer.ExtractToStream(Cache); // parse the Cache.Memory looking for complete JSON messages as needed... end; finally if IdTCPClient1.Connected then Timer1.Enabled := True; end; end; Or, simply move the reading logic into a worker thread and let that thread block as needed, as you said.
-
Your timer code is not reading the data correctly. The Connected() method performs a read operation, so it is likely to receive bytes you are expecting, thus InputBufferIsEmpty() does not return False and you then skip calling AllData(). Which is also the wrong reading method to use, as it reads until the connection is disconnected and then returns what was read. That is not what you want in this situation. The data you are looking for is JSON formatted data, so you should read based on the JSON format. In this particular case, the greeting and WATCH replies are both JSON objects with no nested sub-objects, so it would be good enough to simply read from the starting curly brace to the ending curly brace once you detect data arriving, eg: procedure TForm2.Timer1Timer(Sender: TObject); var ReceivedText: string; begin Timer1.Enabled := False; try with IdTCPClient1 do begin if not Connected then Exit(); // read any data in if IOHandler.InputBufferIsEmpty then begin IOHandler.CheckForDataOnSource(0); IOHandler.CheckForDisconnect; if IOHandler.InputBufferIsEmpty then Exit(); end; IOHandler.WaitFor('{', False); ReceivedText := IOHandler.WaitFor('}', True, True, IndyTextEncoding_UTF8); Memo1.Lines.Add(ReceivedText); // if not already, send streaming command if not SentStreamCommand then begin IdTCPClient1.IOHandler.WriteLn('?WATCH={"enable":true,"json":true}'); SentStreamCommand := True; end; end; finally if IdTCPClient1.Connected then Timer1.Enabled := True; end; end; Though, this really isn't the best way to handle this situation. Knowing that the server always sends a greeting banner, and each request sends a reply, I would simply get rid of the timer altogether and do a blocking read immediately after connecting, and after sending each request. And move the logic into a worker thread so the UI thread is not blocked. But, if you must use the UI thread, a better option would be to find a JSON parser that supports a push model, then you can push the raw bytes you read from the socket connection into the parser and let it notify you via callbacks whenever it has parsed complete values for you to process. Not all replies in the GPSD protocol are simple objects. Some replies can be quite complex, more than the code above can handle. For instance, the reply to a POLL request contains an array of sub-objects. An even better option is to use a pre-existing GPSD library (there are C based libraries available for GPSD, and C libraries can be used in Delphi) and let the library handle these kind of details for you.
-
How can I delete an archive Item using TZipFile class
Remy Lebeau replied to Stéphane Wierzbicki's topic in RTL and Delphi Object Pascal
They are aware of it. Just as they have already fixed other access issues related to helpers, it is likely only a matter of time before they do fix this one too. -
Have you tried toJSON() instead of toString()? procedure TForm1.Button1Click(Sender: TObject); const KEK = '"value\with' + sLineBreak + '{strange}chars/"'; Var s: TJSONString; begin s := TJSONString.Create(KEK); Try Edit1.Text := s.ToJSON; Finally s.Free; End; end; Also, which version of Delphi are you using? Recent versions have made updates to the JSON framework to make it more compliant with the JSON spec.
-
Is there a way to get the wizard name / executable from a nindex?
Remy Lebeau replied to dummzeuch's topic in Delphi IDE and APIs
AFAIK, no. What makes you think another wizard is causing your wizard to crash? Have you tried simply debugging your wizard to find out what is actually crashing in it? Are you unregistering your wizard during IDE SHUTDOWN? What does your wizard actually do, and what dependancies does it really on? -
Firebird, change length of Varchar Primary key column?
Remy Lebeau replied to A.M. Hoornweg's topic in Databases
You can create the new column with NULL as its default value, then populate the column with data as needed, and then alter the column to drop the default value, and update the system tables to mark the column as "not null". However, none of this is necessary if you don't drop the original column to begin with. -
Firebird, change length of Varchar Primary key column?
Remy Lebeau replied to A.M. Hoornweg's topic in Databases
You can increase the column size inline without making a copy and dropping the original. Firebird allows columns to be altered with minimal overhead if the same type is used and just the size is increased. Modifications to an existing column will be disallowed if existing data would be lost/truncated, but that is not the case when increasing the size. However, a PRIMARY KEY cannot be altered, so you have to drop the key first. http://www.firebirdtest.com/file/documentation/reference_manuals/fblangref25-en/html/fblangref25-ddl-tbl.html#fblangref25-ddl-tbl-altraltrcol Try something like this (untested): ALTER TABLE channels DROP CONSTRAINT <NAME_OF_YOUR_PRIMARY_KEY_CONTRAINT>, ALTER COLUMN paramname TYPE VARCHAR(40) CHARACTER SET ISO8859_1, ADD CONSTRAINT <NAME_OF_YOUR_PRIMARY_KEY_CONTRAINT> PRIMARY KEY (paramname); If you didn't give your primary key constraint an explicit name originally, you can use the system tables to find the auto-generated name that Firebird created (it is in the RDB$CONSTRAINT_NAME field in the RDB$RELATION_CONSTRAINTS system table, see Find all column names that are primary keys in Firebird database). -
Win XP app fails to start -- missing bcrypt.dll
Remy Lebeau replied to Kyle_Katarn's topic in ICS - Internet Component Suite
The coder who previously worked on Indy's OpenSSL's support has been MIA for a long time. Any new updates will have to go through me, and I just haven't had any time to do it myself. -
Right, such examples are using [in] and [out] only for function parameters, not for record fields like in efortier's example. I've never seen such attributes used on fields.
-
That is because there are two problems in your code: the JSON string you are passing in to ParseJSONValue() does not represent a JSON object, just a single JSON name/value pair, so your first typecast to TJSONObject will fail. You need to wrap the entire JSON string in angle brackets, since ParseJSONValue() can't return a TJSONPair. The "PROFILE" field is not a JSON array, so your typecast to TJSONArray will fail. The "PROFILE" field is a JSON object instead, so you need to typecast to TJSONObject. Try this instead: procedure TCLOSINGForm.SpeedButton10Click(Sender: TObject); var JsonValue: TJSONValue; JsonObject: TJSONObject; Branch, st: string; begin st := '{iWN5p2qfRFeGKXn1m3iGnDW0Vkl2: {"PROFILE":{"BIRTHDAY":"8\/20\/19","FULL NAME":"","GENDER":"MALE","NATIONALITY":"INDONESIA","NICK NAME":"","OFFICE":"CLOSING SYSTEM","PHONE NO":"","REFERAL UID":"","WEDDING":"8\/20\/19"}}}'; JsonValue := TJSONObject.ParseJSONValue(st); if JsonValue <> nil then try JsonObject := JsonValue as TJSONObject; JsonObject := JsonObject.GetValue('iWN5p2qfRFeGKXn1m3iGnDW0Vkl2') as TJSONObject; JsonObject := JsonObject.GetValue('PROFILE') as TJSONObject; Branch := JsonObject.GetValue('BIRTHDAY').Value; mem.Lines.Add('Parsed BIRTHDAY ' + Branch); Branch := JsonObject.GetValue('FULL NAME').Value; mem.Lines.Add('Parsed FULL NAME ' + Branch); finally JsonValue.Free; end; end;
-
Win XP app fails to start -- missing bcrypt.dll
Remy Lebeau replied to Kyle_Katarn's topic in ICS - Internet Component Suite
Correct. -
Google Play Store - request extension for Delphi apps
Remy Lebeau replied to Darian Miller's topic in Cross-platform
That was posted before I saw Embarcadero had made a deal with Google to offer an extension for apps written in Delphi/C++Builder. Obviously, you should go that route instead. -
his control requires version 4.70 or great of COMCTL32.DLL
Remy Lebeau replied to sjordi's topic in FMX
That was XP, when Visual Styles were first introduced. Doubtful. What you are thinking of is the app manifest needed to enable ComCtrl32.dll v6 so Visual Styles work. Without the manifest, the system default ComCtrl32.dll version is used instead. 4.70 was the version shipped in Win95. XP and later have shipped with 5.82 and 6.x. More likely, there is simply a logic bug in the offending component, either it is not initializing ComCtrl32 correctly, or it is not detecting the active ComCtrl32 version number correctly.- 8 replies
-
- delphi
- rio 10.3.2
-
(and 1 more)
Tagged with:
-
his control requires version 4.70 or great of COMCTL32.DLL
Remy Lebeau replied to sjordi's topic in FMX
What does the call stack look like when the exception is raised?- 8 replies
-
- delphi
- rio 10.3.2
-
(and 1 more)
Tagged with:
-
Ancient. Yes, the IdObjs and IdSys units were removed from Indy well over a decade ago. Any code that references them is severely outdated and needs to be updated to a modern version. The GitHub repository is just a mirror, the real repository is still on SVN instead. So the Git history may not have everything. When the IdObjs/IdSy units were removed, TIdThreadList was replaced with the RTL's standard TThreadList (and various other compatibility classes were likewise replaced with standard equivalents - TIdStrings -> TStrings, etc).
-
Learn How To Deploy Delphi 10.3 Rio Android Apps To Google Play With Android 64-bit Requirements
Remy Lebeau posted a topic in Cross-platform
Interesting reading: http://www.fmxexpress.com/learn-how-to-deploy-delphi-10-3-rio-android-apps-to-google-play-with-android-64-bit-requirements/ -
Google Play Store - request extension for Delphi apps
Remy Lebeau replied to Darian Miller's topic in Cross-platform
https://community.idera.com/developer-tools/b/blog/posts/additional-information-for-the-android-32-bit-extension -
Note, there are a lot more ComponentPlatforms values available than just those shown above: pidAllPlatforms (new in 10.3.2!) pidWin32 pidWin64 pidOSX32 pidiOSSimulator32/pidiOSSimulator pidAndroid32Arm/pidAndroid pidLinux32 pidiOSDevice32/pidiOSDevice pidLinux64 pidWinNX32 pidWinIoT32 pidiOSDevice64 pidWinARM32/pidWinARM pidOSXNX64/pidOSX64 pidLinux32Arm pidLinux64Arm pidAndroid64Arm/pidAndroid64 pidiOSSimulator64
-
For those of us that don't use this feature yet - what happened?
- 9 replies
-
- debug
- inline variables
-
(and 1 more)
Tagged with:
-
Learn How To Deploy Delphi 10.3 Rio Android Apps To Google Play With Android 64-bit Requirements
Remy Lebeau replied to Remy Lebeau's topic in Cross-platform
Also: https://community.idera.com/developer-tools/b/blog/posts/additional-information-for-the-android-32-bit-extension -
String to Date conversion (yet another one)
Remy Lebeau replied to ertank's topic in RTL and Delphi Object Pascal
Indy has StrInternetToDateTime() and GMTToLocalDateTime() functions in its IdGlobalProtocols unit which support both of those formats. -
WinAPI to query if a form is ready to Rock.
Remy Lebeau replied to Tommi Prami's topic in Windows API
You have to be careful with WaitForInputIdle(), though: WaitForInputIdle should really be called WaitForProcessStartupComplete WaitForInputIdle waits for any thread, which might not be the thread you care about -
Best way to check if an internet SMTP server is available?
Remy Lebeau replied to Ian Branch's topic in General Help
Between the time you check connectivity and the time you want to send an email, your Internet connection may go down, or the Internet may encounter problems (DNS outages, DOS attacks, etc), or the server may go into maintenance mode, or .... So, there is no real benefit to checking the connection ahead of time. Simply attempt the connection at the time you actually want to send the email, and handle any errors that may occur at that time. That is your simplest and best option.