Jump to content

Remy Lebeau

Members
  • Content Count

    2349
  • Joined

  • Last visited

  • Days Won

    95

Everything posted by Remy Lebeau

  1. Remy Lebeau

    Enumeration Type as Parameter

    A record constraint can be used so that only value types can be specified for T, and then RTTI used to verify that T is actually an enumeration type (that check can be done at compile-time in XE7+).
  2. Makes sense that a trial version would not include the library sources. Only licensed production versions should.
  3. Remy Lebeau

    TIDMessage extract RFT body

    The entire email. That is why a TNEF is parsed into a new TIdMessage. Yes. Typically no, those are the filename forms that Microsoft uses for TNEF. But the filename is technically under the control of the sender and COULD be different if a non-Microsoft client is sending a TNEF attachment. So you should pay more attention to the attachment's Content-Type rather than its filename.
  4. Remy Lebeau

    How to extend CE licence?

    Did you try removing the Trial license before installing the CE license?
  5. Remy Lebeau

    How to extend CE licence?

    Yes, what? Yes, you answered the question? Or the answer is yes, you installed a Trial license and not a CE license.
  6. Remy Lebeau

    Looping Memo.Text

    Yes, it does.
  7. Remy Lebeau

    TIDMessage extract RFT body

    The TIdMessage.Body can contain any textual format. RTF is just plain text with markup. If there are no attachments, and the RTF is not wrapped in MIME, then it very well could end up at the top-level email body. Which is why you have to check the TIdMessage.ContentType to determine whether you should look for the RTF in the TIdMessage.Body or in a TIdText.Body within the TIdMessage.MessageParts. Yes. See https://www.indyproject.org/2005/08/17/html-messages/ which is written for HTML, but similar logic would apply for RTF, too. That is perfectly fine. That is what MIME is good at - providing multiple representations for the same data. You can certain scan an email for HTML first, then scan it again for RTF, then scan it again for plain-text. Or, just scan it once and handle whichever format you encounter first (which is how MIME is meant to be handled, as representations are supposed to be ordered from least-complex to most-complex). Yes, that is what you should do. No. No, they are actually distinct formats for different kinds of RTF. Then you would have to actually parse the RTF to extract the image data as needed. I can't answer that. I suspect on the Google end, since Google has a web front-end, and can't be sure that browsers can handle RTF. On the other hand, Outlook is known for storing RTF and related attachments in a TNEF file, and then send that in an email as a single attachment. In which case, the TIdMessage will contain an attachment of type 'application/ms-tnef', with a filename of 'winmail.dat' or 'attXXXXX.dat'. You can then extract that attachment and parse it using TIdCoderTNEF.
  8. Remy Lebeau

    null terminated string array

    Which version of Delphi are you using? string is AnsiString in D2007 and earlier, but is UnicodeString in D2009 and later. RegQueryValueEx() operates on BYTES not CHARACTERS. The last parameter outputs the number of BYTES read. This code is assuming that 1 Byte = 1 Char, which is true only when Char is AnsiChar but not when Char is WideChar. When using a generic String to receive the raw bytes, you need to use (iSize div SizeOf(Char)) - 1 for the string's length (assuming the data is null terminated, which it SHOULD BE but is not GUARANTEED to be - use RegGetValue() instead to ensure proper null termination). If the data is terminated property, and you allocate and fill the String properly, then Pos(#0#0) will NEVER find the double-null terminator, since the 2nd #0 is not actually part of the string's length, it will have been cut off by the -1 on the call to SetLength(). Memory for the 2nd #0 will have been allocated, and the Registry will have populated that memory, but Pos() will ignore that memory since it is not part of the string's length. Since you appear to be filling a TStringList, I would suggest something more like this: var sha_str : string; hOpenKey: HKEY; iType, iSize: DWORD; strList: TStringList; P: PChar; begin sha_str := ''; if RegOpenKeyEx(HKEY_LOCAL_MACHINE, 'SYSTEM\CurrentControlSet\Control\Cryptography\Configuration\Local\SSL\00010003', 0, KEY_QUERY_VALUE, hOpenKey) = ERROR_SUCCESS then try iSize := 0; if (RegQueryValueEx(hOpenKey, 'Functions', nil, @iType, nil, @iSize) = ERROR_SUCCESS) and (iType = REG_MULTI_SZ) and (iSize >= SizeOf(Char)) then begin SetLength(sha_str, iSize div SizeOf(Char)); if RegQueryValueEx(hOpenKey, 'Functions', nil, @iType, Pointer(sha_str), @iSize) = ERROR_SUCCESS then begin strList := TStringList.Create; try P := PChar(sha_str); while P^ <> #0 do begin strlist.Add(P); Inc(P, StrLen(P)+1); end; Edit11.Text := strList.CommaText; if strlist.IndexOf('RSA/SHA512') = -1 then begin cxCheckBox6.Checked := True; strList.Append('RSA/SHA512'); end; if strList.IndexOf('ECDSA/SHA512') = -1 then begin cxCheckBox6.Checked := True; strList.Append('ECDSA/SHA512'); end; strList.Delimiter := #0; strList.StrictDelimiter := True; sha_str := strList.DelimitedText + #0; finally strList.Free; end; end; end else cxCheckBox6.Checked := True; finally RegCloseKey(hOpenKey); end; ... tname := dir + 'SHA512_Default' + _dt + '.reg'; RegistryExport(tname,'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Cryptography\Configuration\Local\SSL\00010003'); CleanUpExport(tname,'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Cryptography\Configuration\Local\SSL\00010003', 'Functions'); if RegCreateKeyEx(HKEY_LOCAL_MACHINE, 'SYSTEM\CurrentControlSet\Control\Cryptography\Configuration\Local\SSL\00010003', 0, nil, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, nil, hOpenKey, pdI) = ERROR_SUCCESS then begin RegSetValueEx(hOpenKey, 'Functions', 0, REG_MULTI_SZ, PChar(sha_str), (Length(sha_str) + 1) * SizeOf(Char)); RegCloseKey(hOpenKey); end; end;
  9. Remy Lebeau

    Looping Memo.Text

    That offset parameter is not available in System.Pos() in XE, it was added in XE3. For D2005-XE2, you can use StrUtils.PosEx() instead.
  10. Remy Lebeau

    How to extend CE licence?

    You didn't answer my earlier question about that:
  11. Remy Lebeau

    How to extend CE licence?

    By simply downloading the latest CE version after your CE license expires. A new license will be emailed to you. You can't RENEW a CE license. You have to obtain a NEW license annually. This is clearly stated in the Community Edition FAQs: https://www.embarcadero.com/products/delphi/starter/faq
  12. Remy Lebeau

    How to extend CE licence?

    AFAIK, you simply can't extend a Trial license, or a CE license. But you can obtain a new CE license once your existing CE license has expired.
  13. Remy Lebeau

    How to extend CE licence?

    I wonder if Support is aware that Embarcadero's Community Forums for Delphi/C++Builder no longer exist?
  14. Remy Lebeau

    How to extend CE licence?

    From the CE FAQs, a Trail version and a CE version are two separate things. Did you really install a Trail license before and not a CE license?
  15. Remy Lebeau

    TidTCPClient fails to discover a lost connection

    That depends on which keep-alive you are referring to. If you mean the TCP level keep-alive, then it is a setting of the local TCP stack, so I would suggest enabling it on both ends, for good measure. But, if you are referring to a keep-alive in your protocol level communications, then who initiates the keep-alive depends on the particular design of that protocol. That is a protocol-level keep-alive. If your server is already doing that, then you don't need to enable a TCP level keep-alive on the server end. If it sends a "Hello" and does not get a response back within a few seconds, close the connection. On the client side, if it knows it is idle and should be expecting "Hello" packets, then you don't really need to enable a TCP keep-alive on the client end, either. Just start a timer for 5-ish seconds and if it elapses before a "Hello" packet is received then close the connection, repeating for each expected "Hello". Does the client ever send its own "Hello" packets to the server, if it doesn't see any server-sent "Hello"s for awhile?
  16. Remy Lebeau

    TidTCPClient fails to discover a lost connection

    The only way to detect a closed connection is to perform I/O on the connection and see if it fails. The Connected() method performs a read operation internally. That will detect a *graceful* disconnect fairly quickly. But if the connection is *lost abnormally* (network issues, etc), then by default it may take the OS a long while (minutes, hours) to invalidate the connection, during which time I/O operations will not fail (reads will simply report no data is available to read, and sends will be buffered until the buffer fills up). So, the best way to handle this is to employ timeouts/keepalives in your own protocol code and just close the connection yourself if you detect it is not being responsive enough for your needs. Or, at the very least, enable keepalives at the TCP layer (see the TIdTCPClient.Socket.Binding.SetKeepAliveValues() method) so the OS can invalidate a lost connection sooner rather than later. See above. In the case of an abnormal connection loss, the OS will happily carry on with I/O operations until the connection has been invalidated. In the meantime, outbound data will simply be queued in the socket's internal buffer, until the buffer eventually fills up, blocking subsequent writes. The default time is up to the OS to decide. Which is why you should rely on using your own timeouts/keepalives instead. That is because modern networking software is usually smart enough to invalidate existing connections fairly quickly when users do things like that manually. That wasn't always the case in the past. Neither Indy, nor the OS, care about connections being idle, as long as they are truly alive. But, your network might care about idleness, depending on its setup. No.
  17. Remy Lebeau

    TIDMessage extract RFT body

    Probably because receiving RTF emails is not common. Formatted emails typically use HTML instead. Assuming the RTF is in the email body itself, and not in a separate TNEF attachment (winmail.dat, etc), then it is really no different than handling HTML emails. If the top-level TIdMessage.ContentType is RTF then read the TIdMessage.Body property, otherwise search the TIdMessage.MessageParts collection, in MIME order, looking for a TIdText object that has an RTF media type and then read its Body property. There is no *unit* for handling RTF, unless TNEF is involved, in which case you would have to use the TIdCoderTNEF class to parse the TNEF attachment to extract its inner email into another TIdMessage, and then you can process that email as needed. RTF and "enrighted text" ('text/richedit' is the predecessor to 'text/enriched') are separate formats. It is up to you whether you want to handle them all or not. 'text/rtf' is likely to be the more common format you encounter, if any. See above. That, I can't really answer. I don't know how RTF email encode images. I think they are embedded directly inside the RTF markup itself, not referred to using separate attachments, like in HTML emails. But I'm not sure.
  18. Remy Lebeau

    String into TArray<Byte>

    TEncoding.Unicode represents bytes in UTF-16LE format. VERY RARELY will you ever need to use TEncoding.Unicode (or TEncoding.BigEndianUnicode) in real production code. Most uses of Unicode<->byte conversions involve converting between Unicode and UTFs, or Unicode and charsets. So, it is much more common to use TEncoding.UTF8, TEncoding.Default (TEncoding.ANSI on Windows, TEncoding.UTF8 on POSIX platforms), or TEncoding.GetEncoding(<charset>).
  19. Remy Lebeau

    Catch details on AV

    Agreed. And believe me, it has been requested many many times, but for whatever reason Embarcadero has continued to decide not to provide it.
  20. Remy Lebeau

    Byte Array to String

    Better to use SysUtils.TEncoding.GetString(), then no intermediate AnsiString is needed. procedure TForm1.Button1Click(Sender: TObject); var ANameSpace : Variant; AFolderItem : Variant; AMailItem : Variant; RTFBody : array of Byte; RTFString : String; begin OutlookApplication1.Connect; ANameSpace := OutlookApplication1.GetNameSpace('MAPI'); AFolderItem := ANameSpace.GetDefaultFolder(olFolderInbox); AMailItem := AFolderItem.Items(1); RTFBody := AMailItem.RTFBody; RTFString := TEncoding.Default.GetString(RTFBody); Memo1.Lines.Add(RtfString); end;
  21. Remy Lebeau

    another StrToDateTime question

    Or the GMTToLocalDateTime() function, also in the IdGlobalProtocols unit. StrInternetToDateTime() ignores the timezone specified in the input string and just returns the date/time as-is. GMTToLocalDateTime() adjusts the date/time into UTC using the specified timezone, and then adjusts the UTC into the local timezone on output.
  22. Remy Lebeau

    TIDSmptServer does not receive mail from certain client [Fixed]

    Actually, it should not be, otherwise the OnBeforeMsg event would not be fired, but the log clearly shows that it is. TIdSMTPServer fully supports BDAT. After firing the OnBeforeMsg event, it will read the 350 bytes that the client claims to be sending, and then it will send a 250 reply, and wait for the next BDAT command to arrive. The real issue I see is that the failing client is issuing a QUIT command before sending a final "BDAT ... LAST" command to indicate the email data is done being sent. That is why the OnMsgReceive event is not being fired. I agree, though, that the logging should be expanded to include the server's actual responses.
  23. Remy Lebeau

    List&Label - HWND of preview form

    Did you try the WH_CBT hook, like I suggested? For example: uses ..., Windows; type TPrintLLReportEventHandler = class private FHook: HHOOK; public constructor Create; destructor Destroy; override; procedure OnViewerButtonClicked(Sender: TObject; Button: TViewerButton; var PerformDefaultAction: Boolean); end; { TPrintLLReportEventHandler } var gPrintReportWnd: HWND = 0; function CBTProc(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; begin if nCode = HCBT_ACTIVATE then begin if gPrintReportWnd = 0 then gPrintReportWnd := HWND(wParam); end; Result := CallNextHookEx(0, nCode, wParam, lParam); end; constructor TPrintLLReportEventHandler.Create; begin inherited; gPrintReportWnd := 0; FHook := SetWindowsHookEx(WH_CBT, @CBTProc, HInstance, GetCurrentThreadId); end; destructor TPrintLLReportEventHandler.Destroy; begin if FHook <> 0 then UnhookWindowsHookEx(FHook); gPrintReportWnd := 0; inherited; end; procedure TPrintLLReportEventHandler.OnViewerButtonClicked(Sender: TObject; Button: TViewerButton; var PerformDefaultAction: Boolean); begin if Button = vbExit then begin MessageBox(gPrintReportWnd, ...); end; end; var evh: TPrintLLReportEventHandler; begin evh := TPrintLLReportEventHandler.Create; try MyLLReportInstance.OnViewerButtonClicked := evh.OnViewerButtonClicked; // Show preview here (using LL_PRINT_PREVIEW) finally evh.Free; end; end;
  24. Remy Lebeau

    Behaviour of TListView (Delphi XE)

    Reading the TListItem.Top property calls TListItem.GetPosition() and returns its Y value. GetPosition() calls ListView_GetItemPosition(), which should work the same in virtual and non-virtual modes. The ListView knows the position and sizes of its list items, it just does not know what data they contain in virtual mode. If you call ListView_GetItemPosition() directly, does it return TRUE or FALSE? I use TListView in vsReport style in virtual mode, and I find it better (and more efficient) to use the Win32 API directly rather than using TListItem for most operations. To scroll to a specific item, I call ListView_EnsureVisible(), then if I want that item to appear at a specific position then I call ListView_GetItemRect() (which TListItem.DisplayRect() calls) and ListView_GetTopItem(), and then TListView.Scroll() for the difference. Right, because I said above, a ListView knows the position and size of its items, in virual and non-virtual modes alike.
  25. Remy Lebeau

    List&Label - HWND of preview form

    I don't know what kind of control "TL21_" is supposed to refer to, but if it does not expose access to its HWND, one option would be to use a thread-local WH_CBT hook via the Win32 SetWindowsHookEx() function to receive notifications of every HWND that is created by the thread. For instance, set the hook just before displaying the preview Form, and then release the hook after the Form is ready/closed. Then you will know every HWND that the preview creates.
×