Jump to content

Remy Lebeau

Members
  • Content Count

    3056
  • Joined

  • Last visited

  • Days Won

    139

Everything posted by Remy Lebeau

  1. Your example is checking for 4 bytes, not 8 bytes. And also, presumably @TokenStart should be FTokenStart, which is already a pointer. But, in any case, if the strings are greater than SizeOf(UInt64) in length, you are only using those first 8 bytes for the "key", so you might not end up with unique keys for different string values.
  2. Remy Lebeau

    Upload files from Delphi to PHP

    It should look like this: uses ..., IdMultipartFormDataStream; var PostData: TIdMultipartFormDataStream; begin PostData := TIdMultipartFormDataStream.Create; try PostData.AddFile('upfile', 'C:\path\filename'); IdHTTP.Post('https://server/UPLOAD.PHP', PostData); finally PostData.Free; end; end;
  3. Remy Lebeau

    MakeDWordIntoIPv4Address backwards result on Android

    GStack.LocalAddress is deprecated, you should be using GStack.GetLocalAddressList() instead. Indy does not currently use WifiManager, that operates at the Android Java layer, but since Indy operates at the native layer then it uses Linux APIs instead to enumerate local IPs, namely gethostname()+getaddrinfo() (there is a TODO in IdStackVCLPosix.pas to use getifaddrs() instead, or Android's NetworkInterface or WifiManager). MakeDWordIntoIPv4Address() is deprecated, use MakeUInt32IntoIPv4Address() instead. Alternatively, have a look at TIdIPAddress.IPv4(AsString) (which uses MakeUInt32IntoIPv4Address() internally). But in any case, the input value is expected to be in network byte order, aka big endian, but WifiInfo.getIpAddress() returns an IPv4 address in host byte order, which may be either little endian or big endian, depending on the device. You can use Integer.reverseBytes() to swap the IP's endian if ByteOrder.nativeOrder() is LITTLE_ENDIAN. Seems Indy's own use of MakeUInt32IntoIPv4Address() may be inconsistent, some places use host byte order, some don't. Also, WifiInfo.getIpAddress() is deprecated since Android 12. You should use LinkProperties now.
  4. Remy Lebeau

    Window /client size bug in 10.4

    Possibly. Embarcadero has been playing around with High-DPI support for a few versions now, which can cause weird side effects.
  5. I don't agree, since the failure is coming straight from the Win32 API itself. But there is definitely something fishy going on here. The only thing that makes sense to me is if maybe the window created by AllocateHWnd() was silently destroyed, but the FWinHandle variable wasn't updated to reflect that. What does IsWindow(FWinHandle) report after AllocateHWnd() returns, and when PostMessage() fails? Even if there were no message *pump* to process messages, there would still be a message *queue* (a thread's message *queue* is created the first time the thread calls any function in user32.dll) when the window is created. PostMessage() fails with error 1400 only if the provided HWND is not a valid window, not if the window is valid but no message pump is running. PostMessage() has no concept of whether a pump is running or how often, it only cares if the queue exists and is not full. And the failing code has nothing to do with IntraWeb itself, but rather with the Win32 API directly.
  6. Remy Lebeau

    Chain of two HttpProxyServer servers

    On the client side, I would strongly advise you NOT to bind the TIdTCPClient and TIdHTTPProxyServer to the same local IP/Port at all. Put the destination proxy server's IP/Port in the DEST command itself, and then have the receiving server extract the values from the command, not from the connected socket. Then you can drop the TIdTCPClient connection after sending the DEST command, and even run the TIdTCPClient on a different PC if you wanted to. constructor TRemoteServer.Create(IP: string; Port: Integer); begin IdHTTPProxyServer1 := TIdHTTPProxyServer.Create(nil); IdHTTPProxyServer1.ReuseSocket := rsTrue; IdHTTPProxyServer1.DefaultPort := Port; IdHTTPProxyServer1.OnHTTPBeforeCommand := HTTPBeforeCommandHandler; var handler := IdHTTPProxyServer1.CommandHandlers.Add; handler.Command := 'DEST'; handler.HelpSuperScript := 'Sets caller as a DESTINATION for remote support (usage DEST PIN IP PORT URL)'; handler.OnCommand := DEST_Handler; if (IP <> '') and (Port <> 0) then begin Writeln('Starting server, binding to: ' + IP + '-' + Port.ToString); var bind := IdHTTPProxyServer1.Bindings.Add; bind.IP := IP; bind.Port := Port; bind.ReuseSocket := rsTrue; end else Writeln('Starting server, default binding'); IdHTTPProxyServer1.Active := True; Writeln('Server running, listening on: ' + IdHTTPProxyServer1.Bindings[0].IP + ' - ' + IdHTTPProxyServer1.Bindings[0].Port.ToString); end; procedure TRemoteServer.DEST_Handler(ASender: TIdCommand); begin Writeln(ASender.RawLine); dest_pin := ASender.Params[0]; dest_ip := ASender.Params[1]; dest_port := ASender.Params[2]; dest_url := ASender.Params[3]; Writeln('Address: ' + dest_ip + ' - ' + dest_port.ToString); end; procedure TRemoteServer.HTTPBeforeCommandHandler(AContext: TIdHTTPProxyServerContext); begin if dest_ip <> '' then begin Writeln('Command redirected to DESTINATION: ' + dest_ip + ' - ' + dest_port.ToString); var tempIO := TIdIOHandlerStack.Create(AContext.OutboundClient); tempIO.ReuseSocket := rsTrue; // tempIO.BoundIP := '10.0.2.4'; //IdHTTPProxyServer1.Bindings[0].IP; tempIO.BoundPort := 443; // IdHTTPProxyServer1.Bindings[0].Port; var tempProxy := TIdConnectThroughHttpProxy.Create(AContext.OutboundClient); tempProxy.Enabled := True; tempProxy.Host := dest_ip; tempProxy.Port := dest_port; tempIO.TransparentProxy := tempProxy; AContext.OutboundClient.IOHandler := tempIO; end; end; procedure TForm1.ConnectToRemote(Connection: string); begin HTTPProxyServer.Active := False; HTTPProxyServer.Bindings.Clear; var bind := HTTPProxyServer.Bindings.Add; bind.IP := ...; bind.Port := ...; bind.ReuseSocket := rsTrue; HTTPProxyServer.Active := True; // Tell server we are there IdTCPClient1.Host := <SERVER IP/URL>; //Connection.Split([':'])[0]; IdTCPClient1.Port := <SERVER PORT>; // Connection.Split([':'])[1].ToInteger; IdTCPClient1.Connect; try IdTCPClient1.SendCmd('DEST 4444 ' + bind.IP + ' ' + bind.Port.ToString + ' https://abc.com'); finally IdTCPClient1.Disconnect; end; end;
  7. Remy Lebeau

    How to use tDateTimePicker for BOTH date and time

    Has that been reported as a bug yet? If not, it should be.
  8. Remy Lebeau

    Using COM to update Word docx files

    Try something like this: procedure update_toc(const docx_file: string); var word, doc: Variant; begin word := CreateOleObject('Word.Application'); doc := word.Documents.Open(WideString(docx_file)); doc.TablesOfContents.Item(1).Update; doc.Close(-1); word.Quit; end;
  9. Remy Lebeau

    quality.embarcadero.com not working?

    My usual QP credentials are not working right now.
  10. Remy Lebeau

    How to use tDateTimePicker for BOTH date and time

    That must be a new feature added in 11.0 Alexandria, because in 10.4 Sydney the only options available were still dtkDate and dtkTime. In which case, I would expect there to be a new and easier way to get the full TDateTime value without resorting to parsing the display text manually.
  11. Remy Lebeau

    docwiki.embarcadero.com is not working

    It is not just the load balancer that is having issues. For example, trying to access several pages today, I'm running into a new kind of error:
  12. You can use the connection's OnWork events for that purpose. Just be aware that they are fired in the context of the thread that is performing the transfer, so if that is not the main UI thread then you will have to synchronize your UI updates with the main thread. https://www.indyproject.org/2021/02/10/links-to-old-indy-website-pages-are-currently-broken/ https://web.archive.org/web/20200925081341/http://ww2.indyproject.org/Sockets/Docs/Indy10Installation.EN.aspx That is a build script for C++Builder (hence the C in the filename), not for Delphi. Indy stopped using build scripts for Delphi after D2009. For Delphi, you can just open the project files directly in the IDE and use the Compile and Install options in the Project Manager. Of course, because 1) you didn't remove the old version from the IDE, and 2) the build script only compiles the library binaries, but it does not install them into the IDE. You have to do that step manually. Never use relative paths, always use absolute paths.
  13. That is an extremely old version of Indy, you should upgrade to the latest version, which is 10.6.2. Even if you can't upgrade your IDE.
  14. OK, thanks. The TIdTCPServer.OnExecute event is fired in an endless loop for the lifetime of the TCP connection. The event doesn't care what data is transmitted. That is the responsibility of the code inside of the event to deal with as needed. That doesn't really matter in this case. ReadStream() will handle those chunks internally. The code's use of Write() is sending the file size followed by the file data. Then the code's use of ReadStream() is reading the file size and then reading the file data up to that size.
  15. What errors, exactly? Please be more specific. And, are you really using Delphi XE? That is 12 years old. Are you, at least, using an up-to-date version of Indy? Or, are you are using a 12-year-old version? The code to transfer the file looks fine to me, so you are just going to have to debug deeper. That zip file contains the same client code you originally posted. It does not include the changes I suggested for the client.
  16. You are leaking the TFileStream object. You need to Free() it when you are done using it. You should wrap the call to Write() in a try..finally block for that, in case Write() raises an exception, eg: procedure TForm1.Button3Click(Sender: TObject); var TFLFileOut: TFileStream; begin TFLFileOut := TFileStream.Create(ToDownload.Text, fmOpenRead or fmShareDenyWrite); try Client.IOHandler.Write(TFLFileOut, 0, true); finally TFLFileOut.Free; end; end; Likewise, you should use try..finally here too, to ensure the TFileStream is Free()'d even if an exception is raised. procedure TForm1.ServerExecute(AContext: TIdContext); var TFSFileIn: TFileStream; begin Label1.Caption := 'Arriva qualcosa...'; TFSFileIn := TFileStream.Create(Edit1.Text, fmCreate); try AContext.Connection.IOHandler.ReadStream(TFSFileIn); finally TFSFileIn.Free; end; end; But, more importantly, TIdTCPServer is a multi-threaded component. Its OnExecute event is fired in the context of a worker thread, not the main UI thread. As such, accessing UI controls, such as your TLabel an TEdit controls, is NOT thread-safe. You MUST synchronize with the main UI thread when accessing them, eg: procedure TForm1.ServerExecute(AContext: TIdContext); var FileName: string; TFSFileIn: TFileStream; begin TThread.Synchronize(nil, procedure begin Label1.Caption := 'Arriva qualcosa...'; Filename := Edit1.Text; end end; TFSFileIn := TFileStream.Create(FileName, fmCreate); try AContext.Connection.IOHandler.ReadStream(TFSFileIn); finally TFSFileIn.Free; end; end; Your calls to Write() and ReadStream() are matched up properly, so I cannot see a reason why the received file would be empty, provided that Write() and ReadStream() are actually being called. Did you verify that with your debugger?
  17. Remy Lebeau

    Delphi 2006 to Delphi XE 10.1 VType help

    That code pre-dates Delphi's shift to Unicode in D2009. But vtWideString and vtPWChar did exist prior to that shift. That code simply does not support Unicode strings at all.
  18. BytesOf() for a (Wide|Unicode)String is just a wrapper for TEncoding.Default.GetBytes(), eg: SND := TEncoding.Default.GetBytes(AValue); Note that TEncoding.Default is TEncoding.ANSI on Windows, but is TEncoding.UTF8 on other platforms.
  19. Remy Lebeau

    Delphi 2006 to Delphi XE 10.1 VType help

    In this code, FISize is not a local variable! It is a class member instead. That makes a big difference. That is completely wrong, and shouldn't have worked even before D2009. vtPWideChar and vtAnsiString are completely different and incompatible types, they need to be handled separately (like I showed you earlier). vtPChar (TVarRec.VPChar) is a null-terminated PAnsiChar, whereas vtPWideChar (TVarRec.VPWideChar) is a null-terminated PWideChar, and TVarRec.VAnsiString is a pointer to an AnsiString's internal payload. You can't treat those 3 pointers the same way. For the purpose of this code, TVarRec.VPChar can be used as-is, but TVarRec.VPWideChar would need to be assigned to a temp AnsiString, and TVarRec.VAnsiString would need to be type-casted into an AnsiString, before their characters can be copied into the ShortString (like I showed you earlier).
  20. Remy Lebeau

    Delphi 2006 to Delphi XE 10.1 VType help

    Why not? Can you be more specific about the problems you are having with it? Yes, it is. Where did you get that idea from? Did that code ever work to begin with? The very first thing it is doing is calling SetLength() (twice!) on a ShortString using an uninitialized FISize variable. Did you remove code not shown here? Where is FISize calculated? In any case, vtChar represents an AnsiChar. System.Char was changed from AnsiChar to WideChar in D2009, so you need to handle vtWideChar now, converting/truncating it to an AnsiChar before copying it into your ShortString. I already showed you earlier how to properly handle vtString, vtAnsiString, vtWideString, and vtUnicodeString and copy them into the ShortString. That said, it is really hard to help you when you keep showing PIECES of code, and not the WHOLE code. It is really hard to understand what your target ShortString is supposed to actually look like given various inputs (or why are you even using ShortString to begin with!!!). And you haven't shown ANY examples of what the input array even looks like to begin with.
  21. Remy Lebeau

    Cleaning up some Exception handling...

    E:ErrorCode is not valid syntax, did you mean E.ErrorCode? The original code displays a TaskMessageDlg on an unhandled exception, but regardless of the type of exception raised, any code following the try..except block continues to run normally, With your proposed change, on a re-raise of an unhandled exception, any code following the try..except block won't run anymore. That is a change in program flow, not just a change in error reporting. Is that what you really want?
  22. Remy Lebeau

    TidHTTP TransferEncoding - Chunked

    It does unchunk a chunked response, yes. It does not send chunked requests, though.
  23. Remy Lebeau

    TidHTTP TransferEncoding - Chunked

    TIdHTTP only supports RECEIVING chunked data, it does not SEND chunked data (you would have to chunk the data manually). And, even if it did support SENDING chunked data, it certainly would not do that in an HTTP 1.0 request, since chunking didn't exist until HTTP 1.1. And per the HTTP 1.1 spec, clients are discouraged from SENDING chunked requests unless they know beforehand via outside means that the server can actually receive chunked requests, That is not possible with TIdHTTP alone. Something else must be going on, for instance if your request is passing through a proxy that reformats your request into a chunked request. You need to explain your situation better, and provide actual logs of the HTTP traffic you are seeing, if you can.
  24. Remy Lebeau

    vtString and vtWideString & vtAnsiString

    There has to be more involved than just that. Since the code is indexing into S using P, and it is incrementing P after copying AnsiChars into S, and the code is looped, that implies that the code is storing more than 1 string value into that ShortString. If it were just a matter of converting 1 (Ansi|Unicode|Wide)String to 1 ShortString, the code could be much simpler, using a normal assignment and letting the compiler do all of the hard work. Can you be more specific? I know for a fact that the code I showed earlier is handling UnicodeString correctly. Though, now that I can see your variable declarations and see that P is a Byte not an Integer, there is an extra validation that the code should be doing when copying AnsiChars into S to make sure S doesn't overflow, eg: var I: Integer; P: Byte; S: ShortString; ls: Boolean; ... Len: Integer; Tmp: AnsiString; ... for I := Low(Values) to High(Values) do with Values[I] do case VType of vtString: begin Len := Length(VString^); if (Integer(P) + 1 + Len) > 256 then raise ...; S[P] := AnsiChar(Len); System.Move(VString^[1], S[P+1], Len); Inc(P, Len + 1); ls := I = High(Values); end; vtAnsiString: begin Tmp := AnsiString(VAnsiString); Len := Length(Tmp); if (Integer(P) + 1 + Len) > 256 then raise ...; S[P] := AnsiChar(Len); System.Move(PAnsiChar(Tmp)^, S[P+1], Len); Inc(P, Len + 1); ls := I = High(Values); end; vtWideString: begin Tmp := AnsiString(WideString(VWideString)); Len := Length(Tmp); if (Integer(P) + 1 + Len) > 256 then raise ...; S[P] := AnsiChar(Len); System.Move(PAnsiChar(Tmp)^, S[P+1], Len); Inc(P, Len + 1); ls := I = High(Values); end; vtUnicodeString: begin Tmp := AnsiString(UnicodeString(VUnicodeString)); Len := Length(Tmp); if (Integer(P) + 1 + Len) > 256 then raise ...; S[P] := AnsiChar(Len); System.Move(PAnsiChar(Tmp)^, S[P+1], Len); Inc(P, Len + 1); ls := I = High(Values); end; ... end;
  25. Remy Lebeau

    Window message sent to a component

    You can't mix AllocateHwnd() with message dispatch methods, that is not how the system works. You need to handle the messages directly in the WndProc that you give to AllocateHwnd().
×