Jump to content

Remy Lebeau

Members
  • Content Count

    2316
  • Joined

  • Last visited

  • Days Won

    94

Everything posted by Remy Lebeau

  1. Remy Lebeau

    Access Violation when i free idUDPClient

    Very simple: pre-D2009: Char is AnsiChar String is AnsiString, using ANSI encoded AnsiChars UTF8String is just an alias for AnsiString, it is not guaranteed to be UTF-8 unless it comes from UTF8Encode() post-D2009: Char is WideChar String is UnicodeString, using UTF-16 encoded WideChars UTF8String is a native string type, using UTF-8 encoded AnsiChars In you example, the length will be 4 Chars (after adding the 'A'). How many bytes those Chars will take up depends on the byte encoding you tell the UDPClient to use. In ANSI/UTF-8, ASCII characters are 1 byte each. In UTF-16, they are 2 bytes each. Things get more complex when you start dealing with non-ASCII characters. First off, TIdUDPClient does have a Write() method, it has Send() and SendBuffer() methods instead. In any case, internally TIdUDPClient will convert the String to bytes, and then transmit the bytes. The default encoding used to produce those bytes is US-ASCII, but you can specify a different encoding in the optional AByteEncoding parameter of Send/Buffer(), or by setting the global GIdDefaultTextEncoding variable in the IdGlobal unit. Well, you have to do that anyway, since you are including binary data in your request, not just text. Explicitly tell TIdUDPClient (or any other Indy component) to transmit strings in the desired ANSI encoding. Don't just rely on defaults. It is because your server did not send the response to the correct port on the client. The client sent out the request from port 59114, so that was the port it could receive the response on, but the server sent the response to port 55510 instead. So, the server ignored the source port of the request and sent the response to its own port instead. If the server requires the client to use the same port that the server is using, you will have to set the TIdUDPClient.BoundPort to that port before sending requests (which you seem to have already figured out). Otherwise, fix the server to send the response to the request's actual source port. Indy does not behave differently in a worker thread vs in the main UI thread. It is not dependent on message handling. Your client is sending the request to a subnet broadcast IP (192.168.84.255) instead of to the server's actual IP (192.168.84.128) (why?). And since you are not setting the TIdUDPClient.BoundIP to bind the client to a specific network adapter, that explains why your client is receiving a duplicate copy of the broadcasted request. So, you will have to either: - send to the server's IP directly. - make your client ignore messages that have its own local IP as the source IP. - set the TIdUDPClient.BoundIP to the client's own local IP, then it won't receive broadcasts from itself.
  2. Since there is a lot of talk of COM in this discussion, have a look at the COM tutorials on this website: http://www.techvanguards.com/com/, especially the section on Events and Callbacks.
  3. Yes, it can: Marshalling a Delegate as a Callback Method
  4. Remy Lebeau

    C++Builder 11 - any way of compiling .PAS?

    C++Builder has always included the ability to compile Delphi .pas files that are added to C++ projects. But, if you need to compile Delphi projects for use in C++, then you will need the full Studio.
  5. Remy Lebeau

    Access Violation when i free idUDPClient

    Why are you doing this? This is the root of your crash. You don't own the Binding object, so you have no business destroying it like this. Let TIdUDPClient manage the Binding for you. It will be destroyed automatically when the TIdUDPClient itself is destroyed. The stack trace you have provided clearly shows TIdUDPClient's destructor is trying to access the Binding after you have manually destroyed it, hence the crash. If you really want to destroy the Binding manually, you need to instead set the TIdUDPClient.Active property to False, which will internally close and destroy the Binding if it is currently active: //FUDP.Binding.Destroy; FUDP.Active := False; No. That would just complicate your code further, since TIdUDPServer is asynchronous, whereas TIdUDPClient is synchronous. That being said, I see some other issues with your code... You should wrap the TIdUDPClient in a try/finally block to ensure that it gets Free()'d in case an exception is raised: FUDP := TIdUDPClient.Create(nil); try ... finally FUDP.Free; end; Same with the TMemoryStream. This is a buffer overflow, as l_buf has 5 bytes in it but you are asking Write() to read 6 bytes from it. l_buf is not null-terminated, so if you need it to be then you have to either add an explicit terminator to the string: l_buf := ToBytes('SOREQ'#0, IndyTextEncoding_ASCII); l_memStream.Write(l_buf[0], Length(l_buf)); Or, write the null-terminator separately: const NullTerm: AnsiChar = #0; ... l_buf := ToBytes('SOREQ', IndyTextEncoding_ASCII); l_memStream.Write(l_buf[0], Length(l_buf)); l_memStream.Write(NullTerm, 1); Alternatively, use Indy's own WriteStringToStream() function in the IdGlobal unit: WriteStringToStream(l_memStream, 'SOREQ'#0, IndyTextEncoding_ASCII); WriteStringToStream(l_memStream, 'SOREQ', IndyTextEncoding_ASCII); WriteStringToStream(l_memStream, #0, IndyTextEncoding_ASCII); In any case, you are converting the TMemoryStream data to a TIdBytes for transmission, so you might consider simply getting rid of the TMemoryStream altogether and use Indy's own TIdBytes-oriented functions instead (CopyTIdString(), CopyTIdUInt32(), CopyTIdByteArray(), etc), which are also in the IdGlobal unit: SetLength(l_buf, 6 + SizeOf(l_port) + SizeOf(l_ipBytes)); CopyTIdString('SOREQ'#0, l_buf, 0, -1, IndyTextEncoding_ASCII); l_port := GStack.HostToNetwork(l_port); CopyTIdUInt32(l_port, l_buf, 6); getArrayBytes(l_ip, l_ipBytes); CopyTIdByteArray(l_ipBytes, 0, l_buf, 10, SizeOf(l_ipBytes)); You are not checking to make sure that l_len specifies that enough bytes are actually available to read from l_buf into l_ilUDPData. There is no guarantee that the received datagram is actually as large as your buffer. You are not Connect()'ing the TIdUDPClient to a specific peer, so this line is useless and can be removed. Especially since the next statement is Free()'ing the TIdUDPClient anyway.
  6. Is there more to the error explaining WHY it can't create the instance? For instance, has CoInitialize/Ex() been called beforehand?
  7. Remy Lebeau

    ICS Web Sockets send from server

    You do know that you posted this in a VCL forum, right? ICS has its own forum on this site: https://en.delphipraxis.net/forum/37-ics-internet-component-suite/
  8. Remy Lebeau

    Indy & OpenSSL 1.1.1 & TLS 1.3

    The main reason it hasn't been merged yet is because I just haven't had any time to review it - I don't question that it "works" in general (I've seen enough people say it does), but I still need to see how consistent it fits with the rest of the library, if all of the necessary package/IDE support is in place, how it handles the multiple platforms Indy runs on, etc. The occasional issues being reported in the PR with regards to compiler/runtime errors, etc. As well as this is kind of a big feature to maybe warrant pushing Indy into a new versioning scheme that is long overdue. So, a lot of behind-the-scenes stuff that has made me hesitant to just merge it blindly.
  9. Remy Lebeau

    ExtractFileDir

    How to get path to the parent folder of a certain directory?
  10. 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;
  11. 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":
  12. Um, because it states that it is a password field? <input ... TYPE="password" ... />
  13. 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.
  14. 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.
  15. 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.
  16. 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?
  17. 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
  18. 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.
  19. 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;
  20. 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;
  21. 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.
  22. 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.
  23. 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.
  24. 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
×