Jump to content

Remy Lebeau

Members
  • Content Count

    2943
  • Joined

  • Last visited

  • Days Won

    133

Everything posted by Remy Lebeau

  1. Remy Lebeau

    Guidance on FreeAndNil for Delphi noob

    Sorry, I'm a little late to seeing this... I see it the other way - it can INCREASE the likelihood of an AV (or worse!). The callback's Self pointer will be pointing at memory which the now-dead TMyClass object was occupying. It's undefined behavior for the callback to access that memory for ANY reason, period. But let's forget that for a moment. You nil the FMyVar member when freeing the TMyClass object, with the expectation that you can still access FMyVar later (which you can't). If the memory that FMyVar was occupying gets reused and overwritten before the callback is invoked, that memory might not be zeroed out anymore from the earlier nil. And if it is not, then Assigned(FMyVar) will return True instead of False (if it doesn't just crash outright), and then you will try to call FMyVar.Add(...) and crash... or worse corrupt random memory trying to write to memory that it doesn't own.
  2. Remy Lebeau

    Best approach for using OpenSSL 3.0 in Indy

    AFAIK, that PR works, but is effectively dead as Mezen is no longer working on it. The current efforts that are actively worked on at the moment are: https://github.com/MWASoftware/Indy.proposedUpdate https://github.com/JPeterMugaas/TaurusTLS At some point, I will get this repo released and then updated with whatever new code will work going forward: https://github.com/IndySockets/IndyTLS-OpenSSL
  3. Remy Lebeau

    Guidance on FreeAndNil for Delphi noob

    This doesn't guard against anything. if DoOnCallback() is called after the TMyClass object has been freed then all bets are off. The callback's Self pointer will still be pointing at the memory of the freed object, but that memory MAY OR MAY NOT have been overwritten by the time the callback is executed. You are assuming it has NOT been overwritten yet, but you can't make that assumption. You really should cancel the async operation before/when freeing the TMyClass object, so the callback is not called at all. But, if that is not an option, then a safer option is to keep track of the dead object pointer somewhere and have the callback check if its Self pointer is being tracked as dead before accessing any members.
  4. Remy Lebeau

    Guidance on FreeAndNil for Delphi noob

    Equivalent, but not identical. Do keep in mind that there is one slight difference - FreeAndNil() nils the pointer before destroying the object. It is basically doing this: var tmp := FMyObject; FMyObject := nil; tmp.Free; So, if the call to Free() happened to raise an exception (ie, due to memory issues, or a bad pointer, etc), then the difference is whether FMyObject gets nilled or not. But in normal well-behaving code, this difference is negligible.
  5. Remy Lebeau

    Using a DLL in MSVC

    You will have to call Get8087CW() first and save the value before calling Set8087CW(), then do your work, and then call Set8087CW() again with the value you saved. Do this in each of your exported functions that suffer from the problem.
  6. The only way to make your ObjectIdentifier be a unique type in C++ is to declare it as a class or struct, either with an AnsiString data member, or maybe even derived from AnsiString. You could declare ObjectIdentifier as {$NODEFINE} on the Delphi side. But, you may or may not run into compatibility issues, so you should consider making ObjectIdentifier be a record on the Delphi side and then the compiler can general a compatible struct on the C++ side.
  7. Remy Lebeau

    Using a DLL in MSVC

    If you want to quote multiple messages at one time, you can click on the '+' button on the bottom of each message, and then click the resulting "Quote # posts" popup when ready. If you want to quote multiple sections of a single message, that takes a little more work. In an original message, you can highlight the text you want to quote, then roll the mouse over the selection and click on the resulting "Quote selection" popup. Repeat as needed. Alternatively (on a desktop browser only, don't try this on a mobile browser, it doesn't work well)... after quoting a message, if you put the edit caret inside of the quote text where desired and then insert a few line breaks, SOMETIMES that will automatically split the quote into 2 separate quotes, and then you can add your responses in between them. But, that split does not always work, in which case I end up having to copy/paste/edit the quotes to get what I want. Roll the mouse over a quote and you will see a little box appear in the top-left corner of the quote. Left-click on that box to select the quote as an object, then you can copy/paste the quote, and then edit the quotes as needed. You can also drag&drop quotes using that little corner box, too. Quoting can be a headache, err, art form on this forum! Yes. How would I do that? Adjust these: Default8087CW, DefaultMXCSR, DefaultFPSCR, and DefaultFPSCR Somehow in the older compiler version? Have you read the documentation yet? https://docwiki.embarcadero.com/Libraries/en/System.Default8087CW https://docwiki.embarcadero.com/Libraries/en/System.DefaultMXCSR https://docwiki.embarcadero.com/RADStudio/en/Floating_Point_Operation_Exception_Masks
  8. Remy Lebeau

    TDirectory - file lock out on Win 10 LTSC

    Hard to say. I find it very unlikely that file I/O would report that particular error. It would be helpful to see your actual file I/O and error handling code. I wonder if something is sitting in between your file I/O and error handling that might be affecting the error code unexpectedly. When retrieving the OS error code, you need to retrieve it as close to the failed API call as possible, you can't make any other system calls first. All the more reason why I don't like using IOUtils with all the extra overhead it has, particularly any memory cleanup.
  9. Remy Lebeau

    Using a DLL in MSVC

    I've written a fair share of DLLs in BCB6 that work just fine in other compilers, including MSVC. Never had a problem with that. Makes me think that either you are doing something weird/incompatible that you are not showing, or maybe you are linking in another library into your DLL and that library is incompatible in some way. Hard to say without a reproducible test case. You can call the Form's Update() method to force an immediate repaint. That implies your EXE is calling the DLL functions in a loop that is not processing your UI's message queues in between calls into the DLL. That is not a good design choice, especially for a DLL with a UI. I would suggest either: moving your DLL's UI into a worker thread with its own message loop. having the DLL export a function that the EXE can call periodically to pump your UI's message queue. If the EXE has its own UI, then simply break up the EXE's logic to work asynchronously so its own message loop can also service your DLL's UI. Have you considered using the Remote Debugger? Now we're getting somewhere useful. RAD Studio 12.0 did make changes to how it handles floating-point exceptions: https://docwiki.embarcadero.com/RADStudio/Athens/en/What's_New#Disabling_Floating-Point_Exceptions_on_All_Platforms On older versions, sometimes you do need to adjust the exception masks manually. Particularly for MSVC compatibility.
  10. Remy Lebeau

    Guidance on FreeAndNil for Delphi noob

    Use it ONLY when you NEED it. When freeing an object that is pointed at by a given pointer variable, and that variable may be used again later, then nil'ing that variable makes sense, as future code will be sensitive to what the variable is (or is not) pointing at. But, if the pointer variable is not going to be used after freeing the object, then there is simply no point is nil'ing the variable.
  11. I don't have an older version installed right now to verify this with, but I would expect ALL compiler versions to have a problem with this. Yes, the 'type' specifier in Delphi creates a new distinct type, which you can declare overloads with. But in C++, AnsiString is just a typedef alias for AnsiStringT<0>, and your ObjectIdentifier is just a typedef alias for AnsiString, and thus is also an alias for AnsiStringT<0>. And since typedef just creates aliases, not distinct types, they are both actually the same type, which you can't use to declare overloads with. I'm sure this has come up before in past versions.
  12. Wow. A Microsoft scanner being lenient on an app written by a Microsoft compiler, and harder on an app written by a competitor's compiler. Who would have thought... 😜 And we all know how well AI writes good code...
  13. Remy Lebeau

    Using a DLL in MSVC

    They are using the same DLL instance? That is not how you should make the import lib for MSVC. Use MSVC's command-line DUMPBIN and LIB tools to create a new import lib from the DLL itself. Use DUMPBIN to create a .DEF file for the DLL's exports, and then use LIB to generate a import lib from the .DEF file. Which items are you referring to exactly? There is nothing "bold" in what you showed. You really should not be calling Application->ProcessMessages() at all. What is the actual crash? What is the error message, verbatim? Does the crash happen while the DLL is being loaded into memory, or inside of DllEntryPoint()? Have you tried debugging the DLL in the IDE? Configure your DLL project with your MSVC app exe as its Host. Then put breakpoints in the DLL code as needed. When you run the DLL project, it will execute the MSVC app, which will then load your DLL, and the debugger should attach to it so it can step through the DLL code normally.
  14. Hard to say when you didn't show the Delphi code to compare. On a side note... That is not the correct way to convert a char* string to a std::wstring. That just makes a copy of each char as-is to wchar_t, which does not actually translate the characters from one encoding to another. You need MultiByteForWideChar() or equivalent for that task to avoid data loss/corruption. Since you have a ConvertToWideChar() function, why not use it? Hopefully it does a proper conversion: std::wstring iniFilePath; ConvertToWideChar(exeDir + "\\" + std::string(iniFileName), iniFilePath); Though, why does ConvertToWideChar() take a std::wstring variable as an output parameter, instead of returning the std::wstring? If it did that instead, you could eliminate your wIniFile, wsection, and wkey variables. Why char* here? You are converting from char* to std::string to std::wstring, which is a bit overkill. You could have the array store wchar_t* instead, and get rid of the std::string and std::wstring variables, since WritePrivateProfileStringW() takes wchar_t* strings. If you use std::to_wstring() instead of std::to_string(), you can get rid of these std::string variables and ConvertToWideChar() calls.
  15. I use AVG. You might consider adding an exception to it for your data folder.
  16. Must be something specific on your PC. Using Delphi 12.2 Patch 2 on Windows 10 64-bit, when I create an INI file with the specifications you have described, it takes only 150ms with TIniFile. Switch to TMemIniFile and that drops to under 5ms.
  17. Remy Lebeau

    Modern StandBy

    A TTimer HWND shouldn't change, but any VCL UI control can recreate for any number of reasons. Can't rule anything out at this point. So do it manually. Create a temporary button or something that you can trigger at will to log the current HWNDs, then invoke a standby+wakeup, then trigger the log again and compare the results.
  18. Remy Lebeau

    Modern StandBy

    According to MSDN: TTimer is based on a window-based WM_TIMER message. TTimer has an internal HWND that it receives WM_TIMER messages with. And TMemo is another window-based UI control. Are you ABSOLUTELY SURE that your app's message queue is not generating WM_TIMER messages? Never mind whether they are being DELIVERED to TTimer or TMemo - are they being GENERATED at all? The TApplication[Events].OnMessage event should be able to very that, since it sees all messages coming out of the main thread's message queue. Or even a tool like Spy++ or Winsight. For all we know, your windows got recreated and that is why messages are being lost. Who knows. Did you try verifying that the TTimer's HWND and the TMemo's HWND are still the same before the Standby and after the Wakeup? You are looking at multiple things at one time which are acting on top of each other, and not verifying the behavior at the ROOT of the chain of actions.
  19. Remy Lebeau

    Modern StandBy

    That is highly unlikely. If that were true, then all applications would be dead upon wakeup. I think you are misdiagnosing the problem. But, as I don't have an S0-enabled computer, I can't help you diagnose that better. Have you tried using the TApplication[Events].OnMessage event, and TApplication.HookMainWindow() and overriding the TForm.WndProc() method, to actually check that window messages are really no longer being processed? In any case, an application can detect support for Modern Standby by checking the AoAc field returned by GetPwrCapabilities(). And register for notification of Modern Standby/Resume using RegisterSuspendResumeNotification().
  20. Remy Lebeau

    Looking for containskey when processing data

    True, though it is inherited from TJSONValue and not specific to TJSONObject, it has a little more overhead as it performs path processing on the input string and type validation on the output value, and it requires the caller to declare a variable to receive the output value whether the caller actually wants it or not.
  21. Remy Lebeau

    Looking for containskey when processing data

    TJSONObject does not have a ContainsKey() method, in any version of Delphi. If you want that, you can use a class helper, eg: type TJSONObjectHelper = class helper for TJSONObject function ContainsKey(const AKeyName: String): Boolean; end; function TJSONObjectHelper.ContainsKey(const AKeyName: String): Boolean; begin Result := Self.GetValue(AKeyName) <> nil; end; ... if JSONObject.ContainsKey('keyvalue') then As you can see above, you can use the TJSONObject.GetValue() method, which returns nil if the specified key is not found, eg: if (JSONObject.GetValue('keyvalue') <> nil) then
  22. The coordinates in a mouse event are relative to the client area of the window that is being clicked on. On the other hand, WindowFromPoint() expects screen coordinates instead. Are you accounting for that? But, I don't see how getting the HWND of the preview window is going to help you, since you need the HWND of a particular Form instead. Which goes back to my earlier suggestion to register the preview window's toolbar buttons in such a way that when you receive WM_COMMAND from it you can determine the Form that the event represents. Now you are just delving into OS internals and making this task vastly more complicated on yourself.
  23. Remy Lebeau

    Delphi Community Edition

    No. Even the feature matrix says it should be enabled for CE. No. You have completely separate major releases, so they should coexist fine.
  24. Remy Lebeau

    Reading a section of JSON

    What version of Delphi are you using? Delphi has had a built-in JSON framework for a long time, have you tried it yet? For example: uses ..., System.JSON; var JSON = '...'; var obj = TJSONObject.ParseJSONValue(JSON) as TJSONObject; try for var element in (obj.GetValue('MAILCONFIGS') as TJSONArray) do begin for var pair in (element as TJSONObject) do begin var email := pair.JsonString.Value; var config := pair.JsonValue as TJSONObject; var clientId := config.GetValue('client_id').Value; var appToken := config.GetValue('apptoken').Value; var tempToken := config.GetValue('temptoken').Value; ... end; end; finally obj.Free; end; If your version doesn't have it, there are plenty of 3rd party JSON libraries available.
  25. Remy Lebeau

    idFTP.Put and permission denied

    What is the EXACT error message? What is the class type of the exception that is being raised? Is it EFOpenError (error on the local machine) or EIdReplyRFCError (error on the remote server)? I see several possibilities, you are getting a permission error trying to access the AnyDesk.exe file before the upload begins. the user account you are logging into does not have write permissions on the server the remote directory you are uploading to does not have write permissions.
×