Jump to content

Remy Lebeau

Members
  • Content Count

    2333
  • Joined

  • Last visited

  • Days Won

    94

Everything posted by Remy Lebeau

  1. Remy Lebeau

    ExtractFileDir

    How to get path to the parent folder of a certain directory?
  2. Remy Lebeau

    Does ProgressBar Inside StatusBar Still Working?

    That is because the TProgressBarInStatusBar.CreateIn() code provided earlier is not taking the Left position of the specified TStatusPanel into account, only its Width and Height. So it is positioning the TProgressBar in the wrong place for any TStatusPanel other than the 1st one. Unfortunately, neither TStatusBar nor TStatusPanel provide a property or method to get the Left position of a TStatusPanel, so you will have to retrieve it manually, either by: - looping through the TStatusBar.Panels collection: function GetLeftOfStatusPanel(APanel: TStatusPanel); Integer; var I: Integer; Coll: TStatusPanels; begin Result := 0; Coll := APanel.Collection as TStatusPanels; for I := 0 to APanel.Index-1 do Inc(Result, Coll[I].Width); end; - or by asking the OS directly: uses ..., Winapi.CommCtrl; function GetLeftOfStatusPanel(APanel: TStatusPanel); Integer; var R: TRect; begin SendMessage((APanel.Collection.Owner as TStatusBar).Handle, SB_GETRECT, APanel.Index, LPARAM(@R)); Result := R.Left; end; In which case, since CreateIn() wants the TProgressBar to fill the full rectangle of the TStatusPanel anyway, I would just ask the OS for the rectangle and use it as-is, eg: uses ..., Winapi.CommCtrl; class procedure TProgressBarInStatusBar.CreateIn(const inStatusBarPanel: TStatusPanel; var outProgressBar: TProgressBar; var outLabel: TLabel); var statusbar: TStatusBar; R: TRect; Begin statusbar := inStatusBarPanel.Collection.Owner As TStatusBar; SendMessage(statusbar.Handle, SB_GETRECT, inStatusBarPanel.Index, LPARAM(@R)); outProgressBar := TProgressBar.Create(statusbar); outProgressBar.Parent := statusbar; outProgressBar.Top := R.top; outProgressBar.Left := R.left; outProgressBar.Width := R.Width; outProgressBar.Height := R.Height; outLabel := TLabel.Create(outProgressBar); outLabel.Parent := outProgressBar; outLabel.Align := alClient; outLabel.AutoSize := False; outLabel.Alignment := taCenter; end;
  3. A password field is the only type of <input> element that has masked characters. Unless you are manually masking the characters of a non-password text input field via script? No browser would treat that as a password field. No. Only an <input> field that is explicitly marked as being a password field is treated as a password field. This doesn't just affect Chrome. Per Mozilla's documentation: And, per autocomplete attribute and login fields: Per Preventing autofilling with autocomplete="new-password":
  4. Um, because it states that it is a password field? <input ... TYPE="password" ... />
  5. Remy Lebeau

    Does ProgressBar Inside StatusBar Still Working?

    Or, at the very least, calling Update() on the TProgressBar or TForm. Or, the example shown, by simply using a timer or thread instead of a blocking loop, let the main message queue run unblocked and handle UI updates normally. That being said, TStatusBar is not really intended to host child controls. And using a *drawing* event to update UI layout is a big no-no in general. Any time I've ever needed to show a progress bar inside of a status bar (or, any other non-container parent, such as TListView or TTreeView, etc), I always prefer to owner-draw the parent and actually draw a progress bar myself. I never try to hack in a TProgressBar as a child control. Especially in a parent that can be resized/scrolled at runtime. Keeping a TProgressBar positioned correctly at all times can get ugly quick.
  6. Remy Lebeau

    Duplicated SMTP messages

    Then you will have to talk to your email provider, see if they can trace the source of the duplication while you send test emails to them.
  7. That would be my guess. Most likely a network router thinks the HTTP connection has been idle for too long and is killing the connection. This is a common problem in FTP, for instance, where a long file transfer on a data connection leaves the command connection idle. The TIdFTP component has a NATKeepAlive property to address that issue. You will likely have to enable the same TCP-level keepalive on your HTTP connection, too (ie, by calling the TIdHTTP.IOHandler.Binding.SetKeepAliveValues() method). Otherwise, try switching to a different protocol, like WebSocket, or a custom protocol, that will let you send pings/pongs periodically to keep the connection alive over long periods of idleness.
  8. Remy Lebeau

    Duplicated SMTP messages

    Indy's TIdSMTP does not send duplicate emails, so assuming that: you are not calling TIdSMTP.Send() multiple times do not have the same recipient listed multiple times in the TIdMessage's Recipients/CCList/BCCList properties one of your recipients does not forward the email to another of your recipients Then this duplicating behavior would have to be happening on the server's end, not on Indy's end. If you (or a recipient) looks at the raw source data of the duplicate emails in your/their inbox, are their headers EXACTLY the same? Right down to their reported delivery route, timestamps, etc?
  9. Remy Lebeau

    Load Binary Image From Access DB and show in TImage

    Hmm, I see you've decided to ask your question elsewhere: Delphi Retrieve JPG From Long binary data - JPEG error #53
  10. Remy Lebeau

    How to change the icon of the active tab in TTabControl?

    Personally, I only ever use class helpers when adding new methods/properties to an existing class whose interface can't otherwise be changed yet. That kind of usage is what class helpers were originally intended for.
  11. Remy Lebeau

    How to change the icon of the active tab in TTabControl?

    I generally prefer to use a local accessor class instead: type TTabControlAccess = class(TTabControl) end; TTabControlAccess(TabControl1).UpdateTabImages;
  12. Remy Lebeau

    Load Binary Image From Access DB and show in TImage

    Are you sure all of the images are JPEGs? Try this instead: procedure LoadImageFromBinary; var Image : TJpegImage; Stream: TStream; Blobfield: TField; begin ADOQuery.SQL.Text := 'Select JPEG From Table Where Name=MyName'; ADOQuery.Open; try ADOQuery.First; if not ADOQuery.Eof then begin Blobfield := ADOQuery.FieldbyName('JPEG'); Stream := ADOQuery.CreateBlobStream(Blobfield, bmRead); try Image := TJPEGImage.Create; try Image.LoadFromStream(Stream); Image1.Picture.Assign(Image); finally Image.Free; end; finally Stream.Free; end; else Image1.Picture.Assign(nil); end; finally ADOQuery.Close; end; end;
  13. Remy Lebeau

    What is proper way to crypt some fields?

    Most databases I've seen do not support per-column encryption. So you are likely going to have to manually encrypt your data before inserting it into the database, and manually decrypt the data when pulling it back out. That has nothing to do with FireDAC or the underlying DBMS itself, all you will need from them is a column type that can hold arbitrary data, such as a binary blob field. And yes, you should use salts. Do not store the actual passwords in the encrypted data or in the database. Hash the passwords with a salt and store the hash instead. Recompute the hash whenever you need to compare passwords.
  14. Remy Lebeau

    Getting PID of winword.exe based on filename

    There is no easy way to identify which file(s) a process has open (there are hard ways, though). But you are assuming that WinWord actually keeps the file open, and is not simply reading the whole file into memory and then closing the file, operating on the memory until you save again. You are most likely just going to have to search through window titles to know which WinWord window is operating on which file.
  15. Remy Lebeau

    TSimpleEvent how to

    What exactly are you so confused about? A T(Simple)Event has a state - signaled or unsignaled. You set the initial state when you create the event. You update the state with SetEvent() (signaled) and ResetEvent() (unsignaled), and use WaitFor() to test whether the event is signaled or not, optionally waiting for a period of time to see if an unsignaled event becomes signaled. Period. It is really not more complicated than that. What more do you want to know that the documentation is not already telling you? https://docwiki.embarcadero.com/Libraries/en/System.SyncObjs.TEvent.SetEvent https://docwiki.embarcadero.com/Libraries/en/System.SyncObjs.TEvent.ResetEvent https://docwiki.embarcadero.com/Libraries/Alexandria/en/System.SyncObjs.THandleObject.WaitFor All threads in your process that can access the T(Simple)Event object itself will have rights to call the event's methods. Also, if you assign a name to the event, any thread in another process can open the event by that name. Such a thread will have access to update the event's state if it requests the EVENT_MODIFY_STATE right when opening the event, and access to wait on the event's signaled state if it requests the SYNCHRONIZE right.
  16. Remy Lebeau

    TSimpleEvent how to

    Really? https://docwiki.embarcadero.com/Libraries/en/System.SyncObjs.TSimpleEvent https://docwiki.embarcadero.com/Libraries/en/System.SyncObjs.TEvent https://docwiki.embarcadero.com/RADStudio/en/Waiting_for_a_Task_to_Be_Completed
  17. Remy Lebeau

    TNetHTTPClient and custom header

    Alternatively, these would probably work, too: NetHTTPClient1->CustHeaders->Value["Authorization"] = "Token token=key1, btoken=key2"; NetHTTPClient1->CustHeaders->Add("Authorization", "Token token=key1, btoken=key2"); TNetHeaders AuthHeader; AuthHeader.Length = 1; AuthHeader[0] = TNameValuePair("Authorization", "Token token=key1, btoken=key2"); NetHTTPClient1->Get("https://examplesite", NULL, AuthHeader);
  18. Not relevant in this case, because the handle returned by CreateThread() has THREAD_ALL_ACCESS permissions, which includes THREAD_SUSPEND_RESUME. That permission is meant to prevent other people from suspending/resuming threads they don't have access to. You have full access to your own threads. You are just going to have to debug your app on these failing systems to see what ResumeThread() is actually returning: -1 = failure, what does GetLastError() report? 0 = was not suspended to begin with 1 = was suspended, now resumed (this is what you want in this situation) > 1 = was and still is suspended Not that I'm aware of. The number of threads you can create is limited only by available memory. Even if there were a configurable limit, you would be getting failures in CreateThread(), not in ResumeThread().
  19. In general, there is nothing wrong with creating a TThread with CreateSuspended=False. That has worked just fine for the past 2 decades. So, unless Embarcadero has recently broken TThread, something else is likely going on.
  20. Offhand, the code looks fine to me. I've never had any problems with using TThread with CreateSuspended=False. However, as a workaround, you can try creating the TThread with CreateSuspended=True, and then manually call TThread.Start() after the constructor has exited. If that works, then I would suspect that Embarcdero may have possibly introduced a regression in TThread's construction. What version of Delphi are you using? On Windows, the TThread constructor creates a thread with the CREATE_SUSPENDED flag enabled, then the TThread.AfterConstruction() method calls ResumeThread() if the TThread constructor was called with CreateSuspended=False (as is the case in your example). The error message you are seeing is raised if ResumeThread() fails to resume the thread, ie either because the API failed outright (ResumeThread() returns -1), or the thread was suspended multiple times (ResumeThread() returns > 1), neither of which should be happening in your example. Are you, by chance, calling TThread.Start() anywhere else in your code? If so, you should not be calling Start() on a TThread created with CreateSuspended=False. If that were the case, you would be getting an exception from the TThread constructor, not its AfterConstruction() method.
  21. Remy Lebeau

    How to read file on plugged in Android device

    The device is not accessible via the host machine's file system. There is no local drive letter or UNC share assigned to the device, so you can't use filesystem-based functions to access the device's files. So, you will have to use alternative means of accessing the device's files, such as: Win32 Shell interfaces (IShellFolder/IShellItem, PIDLs, etc) - which is what Explorer uses. Introduction to the Shell Namespace Navigating the Shell Namespace IFileOperation::CopyItem() and IFileOperation::CopyItems Windows Portable Devices API Android Debug Bridge pull command
  22. Remy Lebeau

    How to know how app was started

    On Android, there is a property in FMX (I can't find it right now) that contains the Intent that started the app if it was not already running. You can check that Intent at startup to see if your app was started because of a notification, a file open, etc, depending on how your app manifest is configured. If your app was already running when the Intent is sent, you can register with FMX's RTL to receive TMessageReceivedNotification messages, which will carry the Intent. I'm not sure of the equivalent for iOS, though I do notice that TPushRemoteNotificationMessage and TPushStartupNotificationMessage exist for it.
  23. There are a number of problems with that code: - the wScanCode parameter of ToUnicodeEx() is not optional. Unfortunately, the OnKeyUp event does not give you the original scan code that the OS provided in the WM_KEYUP message. However, in this case, since only bit 15 of the scan code is really needed, you can fake it. For a KeyUp event, bit 15 needs to be set to 1, not 0. - you are not populating the TKeyboardState before passing it in to ToUnicodeEx(). You need to call GetKeyboardState() first. - you are passing in a single WideChar for the output buffer to ToUnicodeEx(), but you are telling ToUnicodeEx() that the buffer is large enough to hold 255 WideChars, which is a lie. The output of the conversion can be more than 1 WideChar, so you need to allocate enough space to hold the entire result. The return value will tell you how many WideChars were actually written to the buffer. - ToUnicodeEx() alters the keyboard state while translating the key, unless you ask it not to (Windows 10+ only). - WideCharToString() expects a null-terminated PWideChar string, not a single WideChar. With that said, try something more like this instead: procedure TForm1.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); var buf: array[0..15] of WideChar; KSta: TKeyboardState; numChars: Integer; begin Winapi.Windows.GetKeyboardState(ksta); numChars := Winapi.Windows.ToUnicodeEx(key, $8000, ksta, buf, Length(buf)-1, 4, 0); if numChars > 0 then begin buf[numChars] := #0; log.Lines.Add('KeyUp : ' + IntToStr(Key) + ' = ' + WideCharToString(buf)); end else if numChars = 0 then log.Lines.Add('KeyUp : ' + IntToStr(Key) + ' = (no translation)') end else log.Lines.Add('KeyUp : ' + IntToStr(Key) + ' = (dead key)'); end; However, if you really want to handle individual key presses, you should be using the OnKeyPress event of the OnKey[Down|Up] events, as previously stated. The OnKeyPress event gives you translated Unicode characters, not virtual key codes. procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char); begin log.Lines.Add('KeyPress : ' + IntToStr(Key) + ' = ' + Key); end;
  24. But, why does it have to be sent char-by-char? That is much harder than sending properly encoded whole strings.
×