Jump to content

Remy Lebeau

Members
  • Content Count

    2990
  • Joined

  • Last visited

  • Days Won

    134

Everything posted by Remy Lebeau

  1. Remy Lebeau

    A native VCL, and not Windows-based, TComboBox control.

    You say you have hundreds of TComboBoxes, but the screenshot above only shows 7 (presumably 11?). If this screen is similar for the rest of the app, where each item on the side list displays its own page with just a handful of ComboBoxes on it, then a simple solution would be to NOT load every page at one time, but instead to load one page at a time only when it is made visible to the user, and then unload it when it is no longer visible to the user. That will greatly speed up your load times, and then you don't have to resort to using hacks like owner-drawing, OnDropDown refreshes, etc. You can move each page to its own TFrame that you create and destroy when needed, that way you still regain design-time support for your page layout.
  2. Remy Lebeau

    GetIt Package Manager Delphi 11.3 Timeout

    Getit has not been restored for versions prior to RAD Studio 12.0 Athens yet.
  3. Remy Lebeau

    A native VCL, and not Windows-based, TComboBox control.

    Some suggestions: don't use WM_SETREDRAW directly. Use the TComboBox.Items.(Begin|End)Update() instead, which will use WM_SETREDRAW internally for you. CB_INITSTORAGE helps, but simply don't waste time putting actual string values in so many TComboBoxes to begin with. Instead, fill them with blank strings, and set their Style property to csOwnerDrawFixed and use their OnDrawItem event to render the actual text whenever a drop-down list is visible. consider using a different UI control, such as a TListBox, or a TListView in vsReport mode. Both have true virtual modes that can handle a lot of items very quickly.
  4. Remy Lebeau

    Use TIdMessage to construct rfc 5322 message?

    Indy does not implement RFC 6854 (I didn't even know that existed). It does implement 822/2822, but I don't recall to what extent it implements 5322 (perhaps just aspects of it?). Most likely, yes, as long as you don't need to use some modern email features, like signing, etc. If you run into problems, let me know. Do be aware that, by default, TIdMessage saves its data to a TStream/file using a dot-transparency format (ie, lines that begin with a period are escaped with an extra period) that is intended for use with the SMTP and POP3 protocols but not with other protocols. So, you will likely need to utilize the class helper in the IdMessageHelper unit, which adds an AUsesDotTransparency parameter to the TIdMessage.SaveTo...() methods, then you can set that parameter to False.
  5. CW_USEDEFAULT is actually typed as 'int' in the Windows SDK (in winuser.h): #define CW_USEDEFAULT ((int)0x80000000)
  6. Indy allows that just fine - provided you adequately serialize access to the socket to avoid multiple threads overlapping their outgoing packets. Although multiple threads CAN send to the same socket provided they don't overlap, it is generally a better idea to handle all of the sends in a single thread instead.
  7. IMHO, just because the constant was DWord doesn't mean the variables should have been DWord.
  8. Did you setup your Connection Profile(s) for the target debugger(s) before invoking the "Attach to Process" dialog?
  9. Oh. I didn't realize that was you.
  10. I was referring to this code: Why were nLeft, etc declared as DWord to begin with and not as Integer, as the Win32 API expects?
  11. Why were your variables declared as DWORD to begin with? The Win32 API represents window positions and sizes as ints, not as dwords.
  12. Which makes sense, as that flag is used primarily with the CreateWindow/Ex() APIs and they accept it as an int, not a dword.
  13. Remy Lebeau

    #409: Add ValueFromIndex[] property to TIdHeaderList

    I appreciate the effort. I have added the info to the existing ticket.
  14. Remy Lebeau

    ListView

    In VCL, I would simply custom-draw an image of a "button" directly onto the ListView item, and then use mouse events on the ListView to detect a click on the "button" to invoke the dialog.
  15. I have opened a ticket on Indy's GitHub repo and will work on a fix: #523: EConvertError in TIdX509.notBefore and TIdX509.notAfter properties for 4-digit years UPDATE: I have now checked in a fix. Let me know if it works.
  16. And even if there was, critical sections are not named kernel objects, so they can't interfere with each other.
  17. Remy Lebeau

    Cannot download the Delphi Community Edition

    The CE installer requires the GetIt server to download various components during installation. But CE is still at version 11, and due to the recent server outages, GetIt has been restored for only RAD Studio 12 so far. They are still working on restoring GetIt for version 11 and earlier. So, it is not surprising that they would disable any downloads for older versions right now.
  18. Not yet, no. Only that the migration is in progress.
  19. Sorry, but you simply can't, as 10.4.2 CE is no longer available. The terms of the CE license require that you download and install the latest CE version every year. No exception. If you need to stick with 10.4.2 then you will have to pay for that license, you can't avoid it. Otherwise, you will have to address the problem that is preventing you from migrating the project to the latest CE version.
  20. Remy Lebeau

    Return value from other application

    Yes, it is possible. If it is just a simple integer, you can return it in the process exit code and then retrieve it via GetExitCodeProcess(). But for anything more complex, you can create an Inter-Process Communication channel between the two apps, such as with a pipe, socket, shared memory, etc and exchange data that way.
  21. Meaning, the server sends something to a client that it did not explicitly ask for. Such as a notification when another client connects/disconnects, or when a client sends a message to other client. Things which can happen at any time, outside of the normal request/response flow of "I want something" -> "Here you go" (solicited). "Oh, BTW, here is something else I have for you but you didn't ask for" (unsolicited). That contains a mix of solicited and unsolicited messaging. The new client connects, gets a greeting, says hello, and gets acknowledged. The client initiated an action and got a direct response before doing anything else. That is solicited messaging. Then, all of the other clients get notified of the new connection. They didn't have to send any requests to receive that event, they are just blindly told that it happened, when it happened. It happened in the background, and they have to passively watch out for it. That is unsolicited messaging. That is unsolicited messaging. Client1 sends a request to the server (solicited), but then the server notifies Client2/etc (unsolicited). Client2/etc did not send a request to receive that event, it/they are blindly told when the event happens. Same thing. All that extra messaging that the server does in the background needs to be handled properly. But if you code your server to just receive a request and send a response, you won't be able to handle that extra messaging at all. And right there is the problem. The code you showed doesn't handle that last part. You can't just write to a given client connection whenever and from wherever you want. You have to serialize your outgoing messaging. Think of what would happen if 2 clients happen to connect/disconnect at the same moment and thus need to notify the same target client. Or if multiple clients send private messages to the same target client at the same moment. You don't want multiple messages to that target client to overlap, that will corrupt your socket communications. So, you must provide some mechanism to make sure that subsequent messages wait their turn while an earlier message is still being written to the socket. That could as simple as putting a critical section or other exclusive lock around socket writes. But, that can cause unwanted blockages in threads that want to write to a socket, so that is where my earlier suggestion to use a per-client queue comes into play instead. That way, only the thread that actually writes the queue to the socket may block, while other threads are free to continue putting new messages into the queue. Well, that is certainly true, if you do the writing in the OnExecute event (as you usually should). But, if OnExecute never writes, only reads, then you can do the writing from another thread. I didn't say anything about a delay.
  22. Locality has nothing to do with it. You are opening the drive with just FILE_SHARE_READ specified by itself. You are telling the OS that you are willing to share access to the drive with other open handles only if they open the drive for read-only access. If anybody else already has the drive open for writing, then you won't be able to open it since you are not willing to share write access. And clearly someone does have the drive open for writing (you can verify this with a tool like SysInternals' Handle or Process Monitor utilities), which is why you are getting the "sharing violation" error. Try adding FILE_SHARE_WRITE for your sharing rights: Handle := CreateFile(..., FILE_SHARE_READ or FILE_SHARE_WRITE, ...); But be aware that this will allow other open handles to potentially write to the drive while you are reading from it. If that is not what you want, then omit FILE_SHARE_WRITE and simply warn your user that you can't gain read-only access to the drive.
  23. In a strictly request/response model, having the server send unsolicited notifications to the client will simply not work (unless they are delivered on a separate channel). When a client sends a request and is waiting for a response, it won't know to expect or handle notifications before the response arrives. And if the client is not waiting for a response, it won't be able to read in notifications at all until it sends its next request. So, you would have to either: cache the notifications per-client and deliver them only in solicited responses. But that means there is possible delay in notifications being delivered. make the client poll the server for the status of other clients periodically. Which is usually not desirable, especially with the sheer number of clients you are dealing with. Otherwise, you have to change your protocol to allow for clients to handle unsolicited notifications while waiting for solicited responses, and to handle unsolicited notifications while no request is pending. This typically requires: the client to read from the connection constantly. the client to include a unique ID in each request. the server to echo that unique ID back in the corresponding response. the server to format/identify notifications and responses in a way that allows the client to differentiate between them. Indy's write buffering is at the byte level when interacting directly with the socket connection. But you will likely need higher level message buffering at the business logic level instead. IOW, you will likely need a per-client thread-safe queue for outgoing messages, and then you can push your responses and notifications into that queue as needed. Then you can have the server's OnExecute event flush the calling client's queue to its connection when it is safe to do so. I've posted examples of that many times before in various forums.
  24. What does GetLastError() return when CreateFile() fails? Does it return ERROR_ACCESS_DENIED (5, ie you don't have rights to open the drive), ERROR_SHARING_VIOLATION (32, ie someone else has the drive open for non-read access, but you are sharing only read access), or something else? Handle := CreateFile(...); if Handle = INVALID_HANDLE_VALUE then begin ErrCode := GetLastError; // <-- what does this return? ... end
×