Jump to content

Remy Lebeau

Members
  • Content Count

    2684
  • Joined

  • Last visited

  • Days Won

    113

Everything posted by Remy Lebeau

  1. 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.
  2. 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.
  3. 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.
  4. 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?
  5. 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
  6. 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.
  7. 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;
  8. 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;
  9. 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.
  10. 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.
  11. 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.
  12. 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
  13. 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);
  14. 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().
  15. 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.
  16. 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.
  17. 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
  18. 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.
  19. 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;
  20. But, why does it have to be sent char-by-char? That is much harder than sending properly encoded whole strings.
  21. Remy Lebeau

    Creating Import Library from DLL (64-Bit)

    Creating a stub .lib to use a Delphi-created DLL
  22. You can't declare a Generic for a stand-alone Set, no. But I'm pretty sure (I haven't tried it lately, though) that you can move the Set into the class, and then use a Generic on the class, eg: type TFPropertiesCpt<T> = class (TInterfacedObject, IFCompteurUpdate) public type TSetOfT = Set of T; private FItems : TDictionary<Integer, rCompteurUpdate<T>>; FProperties : TSetOfT; ... procedure Duplicate(const aValue : TFPropertiesCpt<T>); public ... property Items : TDictionary<Integer, rCompteurUpdate<T>> read FItems write FItems; property Properties : TSetOfT read FProperties; function Add(const aTypeOf: T; const aInc: Integer = 1) : TFPropertiesCpt<T>; function WithInit: TFPropertiesCpt<T>; function WithInfo(const aValue: T; aProc: TProc) : TFPropertiesCpt<T>; function WithMax(const aValue : Integer) : TFPropertiesCpt<T>; function ResetCompteur(const aValue: T): TFPropertiesCpt<T>; overload; ... class function Clone(const aValue: TFPropertiesCpt<T>): TFPropertiesCpt<T>; end; Where T can then be set to any enum type, like TTypeOfProperties, etc.
  23. Remy Lebeau

    Sniffer tool detection function

    Meaning what, exactly? Are you trying to detect when specific tools are installed on the machine your app is running on? If so, then do those tools even provide any means of detecting their installations? Do they create Registry keys for themselves? Do they create file system folders in predictable locations? Do you know how to detect these tools manually, before you code any logic for them? Is that a SPECIFIC tool? Because more than one HTTP debugger exist in the world. What does detecting tools have to do with stopping services? Why can't you just stop the services without the tools? Please explain in more detail EXACTLY what you are trying to accomplish.
  24. Are you using VCL or FMX for the sending app? I do not recommend sending individual characters. Send whole strings instead. And be sure to encode them in a platform-neutral encoding, such as UTF-8. For instance, what you consider to be a single "character" may in fact be composed of multiple Unicode codepoints grouped together to create a grapheme cluster, which can't be obtained in a single UI event or transmitted as a single byte/char. Rather than transmitting characters as they are being typed, I suggest having the user type into an Edit control first, and then when Enter is pressed, or a button is clicked, etc, then send the entire text in one go. That will be much easier to manage. In VCL at least, the OnKey(Down/Up) events deal in "virtual" key codes, whereas the OnKeyPress event deals in character codes. Only because Microsoft decided that the virtual key codes for ASCII characters would be the same numeric values as their ASCII character codes. That is not the case for non-ASCII characters. Correct. Virtual key code 222 (0xDE) is VK_OEM_7: "Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the 'single-quote/double-quote' key" You don't, because there is no ASCII code for that character. The best way to deal with non-ASCII characters is to deal with Unicode strings.
  25. Remy Lebeau

    Delphi JSON data to listbox

    Well, obviously, because you are not calling TJSONObject.ParseJSONValue() to parse the JSON, and then pointing the Obj variable at the JSON object which holds the 'meta_data' field, You have to do that before calling Obj.GetValue('meta_data'). Once again, just like I stated in my very first reply of this discussion, you have not shown the complete JSON document, so I cannot show you complete Delphi code, only snippets. So it is your job to apply those snippets to your actual JSON document as needed.
×