Jump to content

Remy Lebeau

Members
  • Content Count

    626
  • Joined

  • Last visited

  • Days Won

    33

Everything posted by Remy Lebeau

  1. Remy Lebeau

    Variation of FormatDateTime(

    FormatDateTime() and other related functions are meant for formatting a specific date/time, not formatting a duration between 2 date/times. You are going to have to format a duration manually, like Der showed using TTimeSpan.
  2. Remy Lebeau

    Best way to prevent multiple instances? Mutex not working

    No, it won't. SeCreateGlobalPrivilege applies only to file mapping objects, not to mutexes. Anyone can create a mutex in the Global namespace. See https://stackoverflow.com/a/41370046/65863 I see no mention of this anywhere in this discussion before your comment.
  3. You are not resetting the ms1.Position property back to 0 after calling ms1.CopyFrom(fs, fs.Size) and before calling ms2.CopyFrom(ms1, ms1.Size). After ms1.CopyFrom() is done reading from the TFileStream, ms1.Position is at the end of the stream, it is not reset back to 0 automatically. You are then asking ms2 to read ms1.Size bytes from the end of the ms1 stream, hence the error. Calling TStream.CopyFrom() with its Count parameter set to <= 0 will reset the source TStream.Position to 0 and read all of the source TStream's bytes. But you are not doing that, you are setting the Count parameter to the source TStream.Size instead, so CopyFrom() will read from the source TStream's current Position, and fail if the requested number if bytes is not read successfully.
  4. Remy Lebeau

    Delphi 10.4.1 and the IDE FIx Pack

    Correct. Andreas has already gone on record stating that he no longer has a license to paid versions of RADStudio and so will not be able to update IDEFixPack for new IDE versions without their Community Editions. And Embarcadero has already gone on record stating that releasing a 10.4 Community Edition has been delayed, with no ETA stated as of yet.
  5. Remy Lebeau

    Best way to prevent multiple instances? Mutex not working

    A simple mutex will work fine in those cases if you create the mutex in the 'Global\...' namespace so it exists across account/session boundaries. See Kernel Object Namespaces.
  6. Remy Lebeau

    check if App Minimized

    What is the TApplication.MainFormOnTaskbar property set to? If MainFormOnTaskbar is True, then minimizing the MainForm will minimize the MainForm window to the Taskbar. In which case, checking TForm.WindowState or IsIconic(MainForm.Handle) should work. But if MainFormOnTaskbar is False, then minimizing the MainForm will hide the MainForm window and minimize the TApplication window to the Taskbar. In which case, checking IsIconic(Application.Handle) should work.
  7. Remy Lebeau

    Help needed. Re-raising exception gives AV.

    Sure, if you want code higher up on the call stack to catch and handle the original exception as-is. But there are use-cases where it makes sense to raise a new exception instead, in which case you should use the Exception.RaiseOuterException() method so that you can capture the original exception in the InnerException of the new exception so that it is not lost if the higher code needs it.
  8. That is because Win32 structures do not use 1-byte alignment, they use 8-byte alignment. See What structure packing do the Windows SDK header files expect?
  9. Remy Lebeau

    XMLDocument and popup windows

    Have you considered simply changing the TXMLDocument to use a different DOMVendor than MSXML?
  10. Remy Lebeau

    TIdSSLIOHandlerSocketOpenSSL and TLS 1.3 ?

    Sorry, I can't help with that. I know nothing about OpenSSL 1.1.x or the new APIs it introduced. I did not write the new SSLIOHandler for 1.1.x. Are you able to access the same server using other apps that use TLS 1.3? Maybe the server's certificate really is faulty.
  11. Remy Lebeau

    Streaming binary data via TIdHTTPServer

    TIdHTTPServer is not really designed for streaming media. If you don't provide the AResponseInfo with a ContentText or ContentStream value, a default HTML page is sent instead. And if you don't provide a ContentLength value, one is calculated automatically from the ContentText/ContentStream by default. And if you don't send a response before the OnCommand... event handler exits, one is sent automatically. So basically, the only way I see to do what you want is to either: - NOT using HTTP's "chunked" encoding - have your OnCommand... event handler set the AResponseInfo.HeaderHasBeenWritten property to True to disable the server's default response handling, send your own HTTP response headers manually, and then run a loop that sends the raw media samples as needed until finished, and then exit the event handler. - USING HTTP's "chunked" encoding - have your OnCommand... event handler set the AResponseInfo.TransferEncoding property to 'chunked' to disable the server's default ContentLength handling, then call AResponseInfo.WriteHeader() to send the server's default HTTP response headers normally, and then run a loop that sends the media samples (in HTTP chunked format) as needed until finished, and then exit the event handler. There are probably other solutions, like writing a custom TStream class for use with the ContentStream, but that can get a little ugly.
  12. Remy Lebeau

    MsgWaitForMultipleObjects Usage

    In this situation, it is best not to block the main thread at all. Disable the UI if you need to, but let the worker thread and main message queue run in parallel normally, and have the worker thread notify the main thread when it is finished, eg: procedure TForm2.Button1Click(Sender: TObject); var Thrd : TThread; begin Thrd := TThread.CreateAnonymousThread( procedure begin Sleep(10000); end ); Thrd.OnTerminate := ThreadFinished; Thrd.Start; // disable UI as needed ... end; procedure TForm2.ThreadFinished(Sender: TObject); begin Memo1.Lines.Add('Thread finished'); // enable UI as needed ... end;
  13. Remy Lebeau

    proper way to check server up or down in rest application

    The simplest option is to use either TThread.CreateAnonymousThread(), eg: uses ..., System.Classes; procedure TFrmLogin.StartLogin; begin TThread.CreateAnonymousThread( procedure var Success: Boolean; begin try RequestLogin.Execute; Success := RequestLogin.Response.Status.Success; except Success := False; end; TThread.Queue(nil, procedure begin AfterLogin(Success); end ); end ).Start; end; procedure TFrmLogin.AfterLogin(Success: Boolean); begin if Success then begin ShowMessage ('server up'); do something ... end else begin ShowMessage ('server down'); do something else ... end; end; Or similarly, TTask.Run(): uses ..., System.Threading; procedure TFrmLogin.StartLogin; begin TTask.Run( procedure var Success: Boolean; begin try RequestLogin.Execute; Success := RequestLogin.Response.Status.Success; except Success := False; end; TThread.Queue(nil, procedure begin AfterLogin(Success); end ); end ); end; procedure TFrmLogin.AfterLogin(Success: Boolean); begin if Success then begin ShowMessage ('server up'); do something ... end else begin ShowMessage ('server down'); do something else ... end; end;
  14. Remy Lebeau

    Form border Style bsNone Covers taskbar

    My answer applies to FMX as well as VCL, though the details of the implementation will differ between them. To handle the WM_GETMINMAXINFO message in VCL, you can simply override the Form's virtual WndProc() method, or subclass its WindowProc property, or use a message method directly on your Form's class type. But in FMX, those options are not available. There is no WndProc/WindowProc to override/subclass. And FMX dispatches only window messages that FMX itself uses internally. So, you would have to instead manually subclass the Form's HWND directly by using the Win32 SetWindowsLongPtr(GWL_WNDPROC) or SetWindowsSubclass() function.
  15. Not when you take the 2nd sentence into account. But whatever. I reworded my previous comment, just for you.
  16. Remy Lebeau

    proper way to check server up or down in rest application

    The best way to handle that is to perform an actual REST request, and handle any error it may produce. Move the code to a worker thread so that it doesn't block the UI thread.
  17. Remy Lebeau

    Form border Style bsNone Covers taskbar

    Setting the Form's position+size that way is not quite the same thing as actually maximizing the window. That is two different states. If you really want to control the Form's size/position when maximized, have the Form handle the WM_GETMINMAXINFO message. You can use the Screen.WorkAreaRect to help you decide what bounds to set from there. Alternatively, try using the Screen.WorkAreaRest to help you set the Form's Contraints property as needed.
  18. The RTL's TList<T> class does not provide access to elements by reference in the TList<T>.Items[] property, only access by value. You would have to use the TList<T>.List property instead, which gives you access to the underlying dynamic array so you can access the raw element data directly.
  19. Is that a typo? Shouldn't it be "json" instead of "josn"?
  20. Remy Lebeau

    Delphi Registry entries default...

    In the "shell" key, set its "(Default)" value to "option 3". See Specifying the Position and Order of Static Verbs
  21. Not sure if this will help, but you might try calling ActivateClassGroup(TControl) before calling CreateComponent() to create a TControl-derived component. At least in DFM streaming, ActivateClassGroup() can be used to limit the class types that are looked at, to avoid ambiguities with VCL and FMX classes of the same name.
  22. FMX didn't exist yet in D7, there was only VCL. Not easily, and not always. If a component's class name is fully qualified, you could look at the prefix to see if it begins with 'Vcl.' vs 'Fmx.' but that only works for components that are distinctly VCL or FMX, it will not work for classes that are shared by both frameworks, ie classes whose qualified names begin with 'System.', 'Data.', 'Xml.', etc. Otherwise, you could drill into each component's RTTI to see if they derive from Vcl.Controls.TControl vs Fmx.Controls.TControl, but again that only works for VISUAL components that are distinctly VCL vs FMX, but will not work for NON-VISUAL components that derive from TComponent and not from TControl. And, of course, the situation may get more complicated in cases where users (despite being told not to) decide to mix VCL and FMX together into a single project.
  23. In cases where I need the index of a found item, I prefer to have my Find* functions accept an optional parameter to output the index. That way, I can still return a pointer to the actual data and not have to re-index back into the data storage after Find* exits, but I can still use the index for other things as needed. For example: function FindRecord(aID: Integer; vIndex: PInteger = nil): PDataRec; var i: Integer; begin Result := nil; if vIndex <> nil then vIndex^ := -1; for i := Low(Data) to High(Data) do begin if Data[i].DataID = aID then begin Result := @Data[i]; if vIndex <> nil then vIndex^ := i; Exit; end; end; end; Or: function FindRecord(aID: Integer; var vIndex: Integer): PDataRec; overload; var i: Integer; begin Result := nil; vIndex := -1; for i := Low(Data) to High(Data) do begin if Data[i].DataID = aID then begin Result := @Data[i]; vIndex := i; Exit; end; end; end; function FindRecord(aID: Integer): PDataRec; overload; var ignore: Integer; begin Result := FindRecord(aProjectID, aID, ignore); end;
  24. Remy Lebeau

    What is wrong with TStringList

    It is worse than that. It loads the entire file into a local byte array, then it decodes the entire byte array into a single Unicode string, and then it parses that string to extract the lines into individual substrings. So, by the time the TStringList has finished being populated, and before TStrings.LoadFrom...() actually exits, you could be using upwards of 4-5 times the original file size in memory! Granted, this is temporary, and all of that memory gets freed when LoadFrom...() finally exits. But there is small window where you have a LOT of memory allocated at one time.
  25. Remy Lebeau

    What is wrong with TStringList

    You can do something similar using TStreamReader and its ReadLine() method, eg: var Stream := TReadOnlyCachedFileStream.Create('c:\temp\t'); try var Reader := TStreamReader.Create(Stream); try while not Reader.EndOfStream do begin S := Reader.ReadLine; // use S as needed... end; finally Reader.Free; end; finally Stream.Free; end;
×