Jump to content

Remy Lebeau

Members
  • Content Count

    2316
  • Joined

  • Last visited

  • Days Won

    94

Everything posted by Remy Lebeau

  1. Remy Lebeau

    Update hidden file

    Yes, it is. But I didn't notice that initially, I thought it was a String instead (which it should be).
  2. Remy Lebeau

    Update hidden file

    I checked, and overload was added to TFileStream in Delphi 6, when the 3-parameter constructor for passing in Rights was introduced.
  3. Remy Lebeau

    Update hidden file

    I'm aware of that. But I have never seen an example of anyone ever passing an existing file handle to a TFileStream constructor, only to a THandleStream constructor.
  4. Remy Lebeau

    Update hidden file

    I didn't say it was wrong, just that it does not follow what Microsoft says to do.
  5. Remy Lebeau

    Update hidden file

    I said to use THandleStream, not TFileStream. TFileStream does not have a constructor that accepts an external THandle as input. Unless that is a recent addition that has not been documented yet. Sure, eg: procedure TForm1.FormCreate(Sender: TObject); var lFile: THandle; lStrList: TStringList; lStream: THandleStream; lFileName: PChar; lAttrs: DWORD; begin lStrList := TStringList.Create; try ... lFileName := 'D:\temp\0104.txt'; lAttrs := GetFileAttributes(PChar(lFileName)); if lAttrs = INVALID_FILE_ATTRIBUTES then begin if GetLastError() <> ERROR_FILE_NOT_FOUND then RaiseLastOSError; lAttrs = FILE_ATTRIBUTE_NORMAL; end; lFile := CreateFile(lFileName, GENERIC_WRITE, FILE_SHARE_WRITE, nil, CREATE_ALWAYS, lAttrs, 0); if lFile = INVALID_HANDLE_VALUE then RaiseLastOSError; try lStream := THandleStream.Create(lFile); try lStrList.SaveToStream(lStream); finally lStream.Free; end; finally CloseHandle(lFile); end; finally lStrList.Free; end; end;
  6. Remy Lebeau

    Delphi 2006 Indy9 and Indy10 swtich

    Yes, you should be able to simply configure the project's search/library paths to point at the Indy 10 source folders rather than the Indy 9 source folders.
  7. Remy Lebeau

    Indy with Lazarus on Raspberry PI using IPV6 – problem

    That does not necessarily mean that is the interface's IP from the server's perspective for binding. That is just the IP that the LAN uses to reach the device. Do you get meaningful IPv6 addresses from Indy's GStack.GetLocalAddressList() method (not sure if it is implemented for Raspberry Pi)? Do you see that IP in the list?
  8. Remy Lebeau

    Update hidden file

    From the CreateFile documentation: So, you don't have to actually remove the attributes, just match the existing attributes. Which FileCreate() can't do. But you could call CreateFile() directly, and then wrap the HANDLE in a THandleStream if needed.
  9. Remy Lebeau

    TidHTTPServer with SSL in Delphi 10.3.3 and 10.4.2

    You are not taking this change into account: Behavioral change to HTTPS handling in TIdHTTPServer When using non-default HTTP/S ports (as you are), you need to assign an OnQuerySSLPort event handler to tell TIdHTTPServer which port(s) you want to activate SSL/TLS on. In the older version, you could get away with not having that handler, but it is required now.
  10. Remy Lebeau

    How to get json array from string?

    That is because IDLIST is an array (of integers), but you are trying to read it as a string. jso.GetValue('IDLIST') will return a TJSONValue pointer to a TJSONArray, which does not implement the Value() method, so it returns a blank string. You need to type-cast the TJSONValue to TJSONArray and enumerate its elements, eg: var jso: TJsonObject; jsa: TJSONArray; s, RetIDList: string; i: Integer; begin s := '{"RESULT":200, "IDLIST":[1,2,3,4,5]}'; jso := TJsonObject.ParseJSONValue(s) as TJsonObject; if jso <> nil then try ... RetIDList := ''; jsa := jso.GetValue('IDLIST') as TJSONArray; if jsa <> nil then begin if jsa.Count > 0 then begin RetIDList := jsa[0].Value; for i := 1 to jsa.Count-1 do RetIDList := RetIDList + ',' + jsa[i].Value; end; end; ... finally jso.Free; end; end;
  11. Remy Lebeau

    Blogged : Advice for Delphi library authors

    C++ supports abstract classes. But abstract classes in C++ can't be used in all contexts that Delphi supports them. Also, not all of the empty methods are for abstract support, they are simply placeholders to allow descendants to hook into strategic places if they want to.
  12. Remy Lebeau

    Trying to learn Lazarus

    FreePascal/Lazarus's RTL/LCL frameworks are fairly API-equivalent to Delphi's RTL/VCL, about on par with Delphi 7-ish, with a few 2009+ features thrown in (UnicodeString, etc). So, if you have something already working in VCL, it will likely port as-is (or close to it) to Lazarus.
  13. Remy Lebeau

    Is this C++ builders new FORUM ???

    I miss the old newsgroups 😢 None of the newer web-based forums have really matched up to them, in terms of usability, monitoring, organization. It is just not the same.
  14. Remy Lebeau

    Blogged : Advice for Delphi library authors

    My plan for Indy 11 many years ago was very different than the current plan. Originally, Indy 11 was going to be for a bunch of new features I was working on. Then a few years ago, we decided to make Indy 11 be just a maintenance release instead to cleanup the existing codebase (drop old compilers, cleanup ifdefs, etc), and push back new features to Indy 12. The "Restructure" branch currently in the GitHub repo is what will eventually become Indy 11. The majority of the work is already done, it just needs to be brought up-to-date with the latest master branch, rebranded, validate everything builds with the new folder/naming structures, etc.
  15. Remy Lebeau

    Blogged : Advice for Delphi library authors

    But the naming of the DCP would change, and that would break existing projects. At the very least, I would have to issue an advisory and document that any Indy upgrades made past X release would require project updates to continue using Indy. I was waiting until Indy 11 to make that change, since I'm restructuring the packages anyway.
  16. Remy Lebeau

    Comunicate with POS terminal (Ingenico)

    The code I presented is only handling 1 request/response at a time, per the documented flow chart. If there are multiple messages involved in a single transaction, then of course you will have to adjust the code to account for that. In the part where it says "use ReceivedText as needed...", you would have to actually look at the message data, and if it is INSERT CARD then progress to the next state and act accordingly to continue the transaction, not go back to the stIdle state until the transaction is finished. I have posted examples of that MANY times before, in many different forums. Should not be hard to find with some searching around. The best way to handle this is to implement a per-client thread-safe queue for each TIdContext, then your UI thread can push data into the queue of the desired client as needed, and the server's OnExecute event can send queued data for the calling TIdContext when it is safe to do so.
  17. Remy Lebeau

    exit terminates delphi app

    Are you SURE your entire process just terminates immediately when exit() is called, and you are not simply failing to catch an exception that causes your main thread to end? Have you wrapped the Python4Delphi code in a try/except block? I am not familiar with Python4Delphi, but after a quick look through its source code, it appears like it might catch a Python SystemExit exception and raise a Delphi-style EPySystemExit exception into user code. Not sure about that, though. Have you tried catching EPySystemExit?
  18. Remy Lebeau

    Read ASCII file from URL like a file

    WinInet supports both HTTP and HTTPS. InternetReadFile() works just fine with HTTPS resources.
  19. Remy Lebeau

    Blogged : Advice for Delphi library authors

    I just looked at the Pull Request history, and I do see 2 requests that you had submitted and then closed. I don't think I ever saw them while they were open, otherwise I would have merged them. I have merged them now, and I will look into whether your changes should to be merged into other scripts.
  20. Remy Lebeau

    Blogged : Advice for Delphi library authors

    I know. But since Indy has never used LIBSUFFIX, its package project names are suffixed, and so the dcp files are also suffixed. Well, they do use Indy inside some of their own tech, so they need a stable version to link against. But they are supposed to be using a private copy that is separate from the public copy they ship for users. That being said, it is a goal for Indy to eventually be phased out of the IDE releases and move into GetIt instead. But its complicated installation steps (more for C++ than Delphi) makes that difficult right now. I'm hoping to clean that up in Indy 11. True, most IDE releases don't ship with the latest Indy release available at the time. 10.4 did, though (which its Indy is already not the latest anymore).
  21. Remy Lebeau

    Blogged : Advice for Delphi library authors

    Despite the title, that post is shaming Indy much more than it does TeeChart. And at the end, it says: I'm well aware of the issues you raised in that post. OK granted, the .bat scripts are a bit of a mess (I never use them myself, and the only reason they even exist is for supporting C++Builder). But the package names having hard-coded suffixes is not about being sloppy, it is about backwards compatibility. Indy still supports all the way back to Delphi 5 and even 4, which predate the LIBSUFFIX option. And by the time LIBSUFFIX actually became commonly used by component authors, it was too late to update Indy 10 without major breakages in existing user code. There is an open ticket to add LIBSUFFIX support to Indy, which is scheduled to be implemented in Indy 11, when support for old compilers will be dropped. Frankly, I don't know why TeeChart was ever referencing IndyProtocols.dcp in the first place, since Indy has NEVER used non-suffixed package names. IIRC, it might have been CodeGear/Embarcadero that did, at one time, strip off the suffixes in their private copies of Indy that shipped with the IDE. But the official version of Indy has ALWAYS used suffixed package names.
  22. Remy Lebeau

    Enumerating Windows Sounds

    What's wrong with enumerating that folder? That is likely what the dialog is doing. Why do you expect there to be an API that provides that list? Not everything in a system UI has a dedicated API behind it.
  23. Remy Lebeau

    "Value assigned to 'xxxxxxxx' never used" issue..

    As you should be, because THAT value you are assigning to dlgResult at THAT point in the code is indeed NOT being used, so it doesn't matter what value you assign to dlgResult. You are OVERWRITING that value afterwards, at "if FilterID1.Value.IsEmpty then dlgResult := False else dlgResult := True;" hence the compiler warning is correct. The compiler is not complaining that the dlgResult variable itself is not being used. It is complaining that the VALUE you are assigning to the dlgResult variable after FilterID1.Execute() exits is not used, so there is no point in assigning that value at all. I think you need to tweak this code a little. Try something more like this: dlgResult := FilterID1.Execute; if dlgResult then begin FilterValue := Trim(FilterID1.Value); dlgResult := not FilterValue.IsEmpty; end; if dlgResult then begin if not TryStrToInt(FilterValue, iJobNo) then begin MessageBeep(MB_ICONERROR); ShowMessage('An Invalid Job # has been entered!'); end else Break; end else ApplyFilter := False;
  24. Remy Lebeau

    Comunicate with POS terminal (Ingenico)

    Why are you clearing the InputBuffer? If you are reading messages correctly, you should never need to do that. As I said earlier, since the ACK/NAK is only 1 byte, you should use ReadByte() instead of WaitFor(), eg: var b: Byte; b := IdTCPClient1.IOHandler.ReadByte; if b = $6 then // ACK begin // read POS's next message... end else if b = $15 then // NAK begin // failure of previous message you sent... end else begin // unexpected, do something... end; Personally, I would just get rid of the timer completely. Following the flow chart you posted earlier is easier when using blocking I/O operations with the IOHandler's ReadTimeout property, eg: var iTry: Integer; b, lrc: Byte; ReceivedText: string; procedure AddToMemo(const S: string); begin Memo1.SelStart := Memo1.GetTextLen; Memo1.SelLength := 0; Memo1.SelText := S + sLineBreak; end; begin iTry := 0; try IdTCPClient1.IOHandler.DefStringEncoding := IndyTextEncoding_8Bit; IdTCPClient1.IOHandler.ReadTimeout := 1000; repeat IdTCPClient1.IOHandler.Write(...); // send message to POS try b := IdTCPClient1.IOHandler.ReadByte; // wait for ACK/NAK except on E: EIdReadTimeout do begin Inc(iTry); if iTry < 3 then Continue; raise; end; end; if b <> $6 then // not ACK? begin Inc(iTry); if iTry < 3 then Continue; raise Exception.Create('No ACK received'); end; repeat // wait for message... ReceivedText := IdTCPClient1.IOHandler.WaitFor(#3, True, True); lrc := IdTCPClient1.IOHandler.ReadByte; AddToMemo('Received message:' + ReceivedText + Char(lrc)); if (ReceivedText is not valid) then begin IdTCPClient1.IOHandler.Write(Byte($15)); // send NAK Continue; // keep waiting... end; IdTCPClient1.IOHandler.Write(Byte($6)); // send ACK if (ReceivedText is HOLD message) then Continue; // keep waiting... // use ReceivedText as needed... Break; // all done... until False; until False; except on E: Exception do AddToMemo('ERROR! ' + E.Message); end; end; But, if you really want to use a separate timer, you should implement a state machine, eg: type TState = (stIdle, stSendingMsg, stWaitingForAck, stWaitingForMsg, stError); private iTry: Integer; CurrentMsg: string; State: TState; ... procedure TMyForm.AddToMemo(const S: string); begin Memo1.SelStart := Memo1.GetTextLen; Memo1.SelLength := 0; Memo1.SelText := S + sLineBreak; end; procedure TMyForm.IdTCPClient1Connected(Sender: TObject); begin IdTCPClient1.IOHandler.DefStringEncoding := IndyTextEncoding_8Bit; IdTCPClient1.IOHandler.ReadTimeout := 1000; State := stIdle; end; procedure TMyForm.DoSomething; begin iTry := 0; CurrentMsg := ...; State := stSendingMsg; Timer1.Interval := 10; Timer1.Enabled := True; end; procedure TMyForm.Timer1Timer(Sender: TObject); var b, lrc: Byte; ReceivedText: string; begin case State of stSendingMsg: begin try IdTCPClient1.IOHandler.Write(CurrentMsg); // send message to POS except on E: Exception do begin State := stError; Timer1.Enabled := False; AddToMemo('ERROR! ' + E.Message); Exit; end; end; State := stWaitingForAck: end; stWaitingForAck: begin try b := IdTCPClient1.IOHandler.ReadByte; // wait for ACK/NAK except on E: Exception do begin if E is EIdReadTimeout then begin Inc(iTry); if iTry < 3 then begin State := stSendingMsg; Exit; end; end; State := stError; Timer1.Enabled := False; AddToMemo('ERROR! ' + E.Message); Exit; end; end; if b <> $6 then // not ACK? begin Inc(iTry); if iTry < 3 then begin State := stSendingMsg; end else begin State := stError; Timer1.Enabled := False; AddToMemo('ERROR! No ACK received'); end; Exit; end; State := stWaitingForMsg; end; stWaitingForMsg: begin try ReceivedText := IdTCPClient1.IOHandler.WaitFor(#3, True, True); lrc := IdTCPClient1.IOHandler.ReadByte; except on E: Exception do begin State := stError; Timer1.Enabled := False; AddToMemo('ERROR! ' + E.Message); Exit; end; end; AddToMemo('Received message:' + ReceivedText + Char(lrc)); if (ReceivedText is not valid) then begin IdTCPClient1.IOHandler.Write(Byte($15)); // send NAK Exit; // keep waiting... end; IdTCPClient1.IOHandler.Write(Byte($6)); // send ACK if (ReceivedText is HOLD message) then Exit; // keep waiting... // use ReceivedText as needed... State := stIdle; Timer1.Enabled := False; end; end; end;
  25. Remy Lebeau

    tlsv1 alert protocol version

    You need to upgrade to the latest Indy, yes. Indy 10 still supports Delphi/C++Builder 6.
×