Jump to content

Remy Lebeau

Members
  • Content Count

    2322
  • Joined

  • Last visited

  • Days Won

    94

Everything posted by Remy Lebeau

  1. Remy Lebeau

    Convert line endings on paste?

    Not that I'm aware of. But its funny, because the RTL does have an AdjustLineBreaks() function, so it would have been trivial for the IDE to adjust pasted text to the editor's native format.
  2. Remy Lebeau

    Intercept "WM_COPY" on Windows

    COleDataSource is just a Microsoft C++ helper class that implements the IDataObject interface, which can be put on the clipboard using the OleSetClipboard() function. In Delphi, you would have to implement the IDataObject interface manually (it is declared in the Winapi.Ole2 unit), or use a 3rd party implementation, such as from Melanders' Drag&Drop suite (probably via TDropEmptySource+TDataFormatAdapter).
  3. Remy Lebeau

    Intercept "WM_COPY" on Windows

    All the more reason to try the route I suggested. Application A could send its file list to Application B, then B can immediately put CFSTR_FILEDESCRIPTOR and CFSTR_FILECONTENTS items on its local clipboard for each file, having each CFSTR_FILECONTENTS hold an IStream to access its file data. Then, when the user pastes the clipboard somewhere (or an app reads the clipboard directly), the individual CFSTR_FILECONTENTS streams can/will be read from, which can then transfer the actual file data from machine A to B as needed. You could even go as far as having A transfer the file data to B in the background while waiting for a paste to happen, caching the data locally on B, and when CFSTR_FILECONTENTS is read from it can read from the local cache if available, otherwise initiate/wait-for the transfer to finish (even provide the data while it is begin transferred). When the clipboard gets cleared, the IStream's will be released, and their destructors can cancel any transfers in progress and delete any local caches as needed. There are examples/tutorials online about working with CFSTR_FILEDESCRIPTOR/CFSTR_FILECONTENTS, for instance: https://www.codeproject.com/Articles/15576/How-to-drag-a-virtual-file-from-your-app-into-Wind https://www.codeproject.com/Articles/23139/Transferring-Virtual-Files-to-Windows-Explorer-in I'm sure they have, but it is very specialized work, so you are not likely to see it talked about publicly very much.
  4. Remy Lebeau

    Intercept "WM_COPY" on Windows

    That is the OLD way to monitor the clipboard. Since Vista, the NEW way is using a Clipboard Format Listener instead, registered via AddClipboardFormatListener() and handling WM_CLIPBOARDUPDATE messages. Have you read Microsoft's documentation on Transferring Shell Objects with Drag-and-Drop and the Clipboard and Handling Shell Data Transfer Scenarios yet? Per Shell Clipboard Formats, you will likely want to implement the CFSTR_FILEDESCRIPTOR and CFSTR_FILECONTENTS formats. That way, you can put descriptions of the files onto the clipboard, and when they are pasted then you can stream in the actual file data as needed.
  5. Remy Lebeau

    Error using Indy

    When your code is calling TIdHTTP.Post(), if it catches any non-HTTP exception, it is reading the TIdHTTP.ResponseCode property, which won't have a valid number in that case and so returns -1. Indy does, in fact, raise an exception if the OpenSSL DLLs are missing or otherwise are unable to be loaded - EIdOSSLCouldNotLoadSSLLibrary. After that exception is raised, you can call Indy's WhichFailedToLoad() function in the IdSSLOpenSSLHeaders unit, and it will tell you whether the DLLs themselves could not be loaded, or whether any of the required exports are missing (ie, because the DLLs are the wrong version for what Indy is expecting). There are other exception classes you can catch for other OpenSSL-related errors, too. Most of them derive from either EIdOpenSSLAPISSLError or EIdOpenSSLAPICryptoError, both of which provide error codes. For example: try FidHttp.Post(FURL, Params, FResponse); FResponseCode := FidHttp.ResponseCode; FResponse.Seek(0, soFromBeginning); except on E: EIdHTTPProtocolException do begin FResponseCode := E.ErrorCode; ErrorEvent(Self, 'HTTP Protocol Exception:' + #$D#$A + AdjustLineBreaks(E.ErrorMessage, tlbsCRLF)); ErrorEvent(Self, 'HTTP Protocol RawHeaders=' + #$D#$A + FidHttp.Request.RawHeaders.Text); end; on E: EIdOSSLCouldNotLoadSSLLibrary do begin FResponseCode := -1; // or whatever you want ErrorEvent(Self, 'SSL/TLS Library Exception: ' + E.Message); ErrorEvent(Self, 'SSL/TLS Didnt Load=' + #$D#$A + WhichFailedToLoad); end; on E: EIdOpenSSLAPISSLError do begin FResponseCode := -1; // or whatever you want ErrorEvent(Self, 'SSL/TLS API Exception: [' + E.ClassName + '] ' + E.Message); ErrorEvent(Self, 'SSL/TLS API ErrorCode=' + IntToStr(E.ErrorCode)); ErrorEvent(Self, 'SSL/TLS API RetCode=' + IntToStr(E.RetCode)); end; on E: EIdOpenSSLAPICryptoError do begin FResponseCode := -1; // or whatever you want ErrorEvent(Self, 'SSL/TLS Crypto Exception: [' + E.ClassName + '] ' + E.Message); ErrorEvent(Self, 'SSL/TLS Crypto ErrorCode=' + IntToStr(E.ErrorCode)); end; on E: Exception do begin FResponseCode := -1; // or whatever you want ErrorEvent(Self, 'Unknown Exception: [' + E.ClassName + '] ' + E.Message); end; end;
  6. Remy Lebeau

    Error using Indy

    What exactly is reporting that error? Can you provide the exact and complete error message? And what does your code look like? That is not very helpful. Anything is possible, though you should be getting a different error if that were the case. More likely, those PCs are probably running firewalls that are blocking your connection. The 2 OpenSSL DLLs, libeay32.dll and ssleay32.dll. And make sure they are for OpenSSL 1.0.2u or earlier, as TIdSSLIOHandlerSocketOpenSSL does not support newer versions. You can get those DLLs from https://github.com/IndySockets/OpenSSL-Binaries If you want to use newer DLLs, use this WIP SSLIOHandler instead.
  7. Remy Lebeau

    Question about formatting

    This is entirely a matter of personal choice. The compiler doesn't care one way or the other, it ignores whitespace between language tokens. So use whichever format is easier for you to read/write. Personally, I don't use whitespace around '->'.
  8. Remy Lebeau

    Loop a Delay in a thread??

    Seriously? Can't you just use a standard For loop? I don't understand the issue.
  9. Remy Lebeau

    Feature Request - TIdServerIOHandler.Accept

    It doesn't make sense to derive from TIdListenerThread since it is tied to TIdTCPServer and TIdScheduler. From your earlier description, it sounds like you don't even want to use TIdTCPServer at all, since you have your own threads, you just want Indy's wrappers around socket I/O, right? If that is all you need, you could try creating TIdTCPConnection and TIdSSLIOHandlerSocketOpenSSL objects and assign your own socket to the IOHandler.Binding.Handle property. I'm not saying it can't be. I'm just saying it is a new feature that should be submitted to Indy's issue tracker. On a side note: I will mention that although TIdServerIOHandlerSocket.Accept() does not use the TIdYarn parameter, TIdServerIOHandlerChain.Accept() in the SuperCore package (a dead project) did use it.
  10. Remy Lebeau

    Drawing on canvas

    Clipping is the right solution. But ClipRect() won't work for FMX. In FMX, to clip a drawing to a rectangular area, use the TCanvas.IntersectClipRect() and TCanvas.ExcludeClipRect() methods. To clip in a non-rectangular area, use TCanvas.DrawPath() and TCanvas.FillPath() instead.
  11. Remy Lebeau

    FMX-TTreeview: Intercept click on Expand-button

    Too bad FMX's TTreeViewItem doesn't have a ShowButtons property, like VCL's TTreeNode does. So unfortunately, in FMX you have no choice but to populate the immediate child nodes just for TTreeViewItem to decide for itself whether or not to display its expand button (ie, when its VisibleCount is > 0). You don't need to scan the full 2nd level right away, though. When creating a new TTreeViewItem, just scan enough to discover its 1st subfolder and then stop scanning. You can't accomplish that with any of the TDirectory methods, but you can with FindFirst()/FindNext(). Or, you could just use a dummy child node instead, no scanning needed. Either way, when the TTreeViewItem is then expanded for the first time, you can then (remove the dummy and) do a full scan of the 2nd level to finish populating the TTreeViewItem with all of the child nodes as needed.
  12. Remy Lebeau

    FMX-TTreeview: Intercept click on Expand-button

    Why not Expand() instead? That is the method which calls the OnExpanded event handler after CanExpand() says it is OK to do so. All I see available is TTreeView.ItemExpanded(), but it is not virtual, so you can't override it. Internally, TTreeViewItem has an FButton member of type TCustomButton which it assigns an OnClick handler to. That handler simply toggles the TTreeViewItem.IsExpanded property, which calls TCustomTreeView.ItemExpanded(), which doesn't fire any events about the state change into user code, AFAICS.
  13. Remy Lebeau

    Feature Request - TIdServerIOHandler.Accept

    Feature requests should be directed to Indy's GitHub issue tracker: https://github.com/IndySockets/Indy/issues TIdServerIOHandler was never intended for that purpose, or intended to be used outside of TIdTCPServer.
  14. Remy Lebeau

    bitmap is not displayed

    Using System.SysInit was intentional to get to the global HInstance variable. But you are right, I needed Winapi.Messages, too. I have now added it. Good catch. That was a copy/paste error as I was reorganizing the code. I have now fixed it.
  15. Remy Lebeau

    Sorting two lists in step?

    Why are you using two TStringLists, and not a single TStringList that holds 'name=value' pairs? Or, at least a TList that holds TPair<String, Integer>? If you insist on using TStringList, then I would store the indexes of the 2nd list in the Objects[] property of the 1st list. That way, no matter how the 1st list is sorted, the indexes will still match up.
  16. Remy Lebeau

    bitmap is not displayed

    There is a LOT of things wrong with the code you have shown. Starting with the fact that you are trying to draw onto your window from outside of a WM_PAINT message handler. You need to move that logic inside your WndProc() function instead. Or, the fact that you are giving invalid data to CreateBitmapIndirect(), or that you are setting up your HDCs incorrectly. Try something more like the following instead: program ForumBitmap2023; {$APPTYPE GUI} uses System.SysInit, Winapi.Messages, Winapi.Windows; var hBmp: HBITMAP; function WndProc(hWnd: HWND; uMsg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; var PS: TPaintStruct; hOldBmp: HBITMAP; hdcBmp: HDC; begin Result := 0; case uMsg of WM_CREATE: hBmp := LoadImage(0, 'C:\Paints.bmp', IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); end; WM_DESTROY: begin DeleteObject(hBmp); PostQuitMessage(0); end; WM_PAINT: begin BeginPaint(hWnd, PS); hdcBmp := CreateCompatibleDC(PS.hdc); hOldBmp := SelectObject(hdcBmp, hBmp); BitBlt(PS.hdc, 30, 10, 620, 489, hdcBmp, 0, 0, SRCCOPY); SelectObject(hdcBmp, hOldBmp); DeleteDC(hdcBmp); EndPaint(hWnd, PS); end else Result := DefWindowProc(hWnd, uMsg, wParam, lParam); end; end; var cls: WNDCLASSEX; hWnd: HWND; msg: TMsg; begin ZeroMemory(@cls, Sizeof(cls)); cls.cbSize := Sizeof(cls); cls.style := CS_HREDRAW or CS_VREDRAW; cls.lpfnWndProc := Addr(WndProc); cls.cbclsExtra := 0; cls.cbWndExtra := 0; cls.hInstance := HInstance; cls.hIcon := LoadIcon(0, IDI_APPLICATION); cls.hCursor := 0; cls.hbrBackground := COLOR_HIGHLIGHTTEXT + 1; cls.lpszMenuName := nil; cls.lpszClassName := 'Window'; cls.hIconSm := LoadIcon(cls.hInstance, IDI_APPLICATION); RegisterClassEx(cls); hWnd := CreateWindow(cls.lpszClassName, 'Program', WS_OVERLAPPED or WS_SIZEBOX, 300, 100, 700, 500, 0, 0, cls.hInstance, nil); ShowWindow(hWnd, SW_SHOW); UpdateWindow(hWnd); while GetMessage(msg, 0, 0, 0) do begin TranslateMessage(msg); DispatchMessage(msg); end; ExitCode := msg.wParam; end.
  17. Remy Lebeau

    bitmap is not displayed

    BOOL is an integer. The Windows.BOOL type is defined as a LongBool. Don't confuse BOOL with Delphi's native Boolean type. See: BOOL vs. VARIANT_BOOL vs. BOOLEAN vs. bool It returns -1 when it is passed invalid parameters, see: When will GetMessage return -1? Besides, assuming no memory corruption has occurred, it is otherwise physically impossible for a thread's message queue to be destroyed while the thread is still running, and a thread can't retrieve messages for other threads.
  18. Remy Lebeau

    Confused on two things

    Yes, that code is wrong. The end's are unbalanced, and the semicolon on the 1st WriteLn doesn't belong there. Yes, that code is correct.
  19. Remy Lebeau

    Confused on two things

    Please do. The only way that could happen is if the compiler is interpreting the 'end' as belonging to a 'begin' at the top-level of the unit itself, not in a nested control block, eg: unit <name>; function DoIt; begin // <-- nested if <condition> then begin // <-- nested ... end else begin // <-- nested ... end; // <-- ; here end; // <-- ; here begin // <-- top-level ... end. // <-- . here If you believe your 'end' is not the final 'end' of the unit, then you probably missed a 'begin' somewhere above it. Hard to say without seeing your actual code. That is correct in most cases. The exception being the top-level 'begin..end' of a unit, which uses dot instead of semicolon. Neither can we, since we can't see your actual code. That is wrong if the statement is not inside a 'begin..end', eg: if <condition> then <statement> // <-- OK else ... if <condition> then begin <statement>; // <-- OK end else if <condition> then <statement>; // <-- wrong else Programs and Units (Delphi): The_Block Declarations and Statements (Delphi): Compound Statements Declarations and Statements (Delphi): Blocks and Scope
  20. It's possible that some stack unwinding does occur, but the call stack you provided earlier clearly shows that the exception handler makes a bunch of function calls, which could easily eat up whatever stack space was freed up. Pretty much, yes. A thread has a fairly limited call stack available to it. The stack can grow only so much before it overflows. That is why it is not a good idea to put a lot of data on the stack in the first place. However, you can set the limits in the project options, if you need them higher. Just know that doing so can affect all threads created at runtime (unless overwritten in code on a per-thread basis).
  21. Remy Lebeau

    Tmapimail

    Not directly, no. You would have to write and install custom software on the host computer for your VM program to connect to and send its report data to, and then that software can use MAPI to email the report data as needed. Perhaps write a custom DCOM component that the VM program can instantiate remotely and proxies the MAPI object itself. Or maybe write a custom SMTP server. Or use a remote-accessible IPC mechanism such as named pipes. TCP sockets, RPC, etc.
  22. Makes sense why it would fail. A stack overflow means there is no more stack space available to push new data onto. In x86, all of those extra function calls are going to keep trying to push data onto the call stack. Eventually something has to give way. Moral of the story - don't overload the call stack in the first place!
  23. Remy Lebeau

    Creating multiple threads in a DLL

    Sounds like you (or the host app) are not actually creating new threads to call your DLL functions, instead you/it are just calling your DLL functions in the context of an existing thread. Anything is possible. Without seeing your actual DLL code, and without seeing some code/documentation about the host app's plugin interface, how do you expect anyone to help you?
  24. Remy Lebeau

    I need the console window to stay open

    'end;' terminates compound statements, case statements, scope blocks, class/record declarations, etc. See Declarations and Statements (Delphi) 'end.' terminates only a unit block. See Programs and Units (Delphi) You should read the Delphi Language Guide for all the syntax rules.
  25. Remy Lebeau

    Assign KeyDown function to btnClick

×