Jump to content

Remy Lebeau

Members
  • Content Count

    2684
  • Joined

  • Last visited

  • Days Won

    113

Everything posted by Remy Lebeau

  1. Remy Lebeau

    Patch a private virtual method

    Not a copy, but the original. All object instances of a class have their own copies of data members, but they all share a single set of code, vtables, etc in memory. So, patching a method of a class will affect all object instances of that class. Not sure I understand what you are asking.
  2. Remy Lebeau

    DL a file from the web

    It raises an exception on error. However, internally it uses Windows' Urlmon.URLDownloadToFile() function, which is notoriously buggy, and crappy at reporting errors.
  3. No. First, not even considering threads yet, TApplication is simply not designed to run multiple instances at a time. There are globals that it uses internally which it assumes it has exclusive access to, and will not share well with other instances. Also, there is plenty of code inside of the VCL that assumes there is only 1 global TApplication object, and won't even consider the existence of other instances. Second, considering threads, the VCL is simply not thread-safe to begin with. It is not designed to be used in multiple threads at a time. VCL controls are expected to be used only in the main UI thread which runs the single global TApplication object. Also, the VCL runs on top of the Win32 API, and API window handles have an affinity to the thread that creates them, which restricts which threads are allowed to access them. And VCL controls simply don't react well when those window handles get messed up when accessed across thread boundaries. Don't do it. That is a very bad design choice. Handle all of your UI needs in the default main UI thread only. You can use multiple worker threads to handle your business logic however you want, and you can create a separate TForm to associate with each worker thread if that is what you need. Just make sure that any data you share across threads is adequately protected from concurrent access, and that you have worker threads synchronize with the main UI thread whenever they need to access the UI.
  4. Those are not valid Delphi declarations. Those are valid Delphi declarations (well, almost - Write() needs a semicolon instead of a comma between Buffer and Count). They work the same as they do in C++. Most likely, you are simply passing in the wrong values, so you end up reading/writing data from the wrong memory addresses. Hard to say since you did not show the code you are having trouble with. In Delphi, an untyped 'const'/`var' parameter is just a reference to a memory address, so you can pass in whatever variable you want and the compiler will pass in the memory address of that variable. In C++, the closest equivalent to that is a '(const) void*' pointer, using the '&' operator to get the address of a variable. So, in Delphi, to read/write data from/to an array, for instance, you would pass in the 1st element of the array, and the compiler will pass in the memory address of that element. On the other hand, if you have a pointer to memory, you would have to dereference the pointer so the parameter can receive the memory address of the thing being pointed at. Here is a few examples using different types of memory: var Value: Integer; ComPort.Read(Value, SizeOf(Value)); ComPort.Write(Value, SizeOf(Value)); var Buffer: array[0..255] of Byte; ComPort.Read(Buffer[0], SizeOf(Buffer)); // or: ComPort.Read(Buffer, SizeOf(Buffer)); ComPort.Write(Buffer[0], SizeOf(Buffer)); // or: ComPort.Write(Buffer, SizeOf(Buffer)); var Buffer: array of Byte; SetLength(Buffer, ...); ComPort.Read(Buffer[0], Length(Buffer)); // or: ComPort.Read(PByte(Buffer)^, Length(Buffer)); ComPort.Write(Buffer[0], Length(Buffer)); // or: ComPort.Write(PByte(Buffer)^, Length(Buffer)); var Str: AnsiString; SetLength(Str, ...); ComPort.Read(Str[0], Length(Str)); // or: ComPort.Read(PAnsiChar(Str)^, Length(Str)); ComPort.Write(Str[0], Length(Str)); // or: ComPort.Write(PAnsiChar(Str)^, Length(Str)); var UStr: UnicodeString; SetLength(UStr, ...); ComPort.Read(UStr[0], Length(UStr) * SizeOf(WideChar)); // or: ComPort.Read(PWideChar(Str)^, Length(UStr) * SizeOf(WideChar)); ComPort.Write(UStr[0], Length(UStr) * SizeOf(WideChar)); // or: ComPort.Write(PWideChar(Str)^, Length(UStr) * SizeOf(WideChar)); type PMyRec = ^TMyRec; TMyRec = record Value: Integer; ... end; var Ptr: PMyRec; NumBytes: Integer; NumBytes := SizeOf(TMyRec) * ...; GetMem(Ptr, NumBytes); ComPort.Read(Ptr^, NumBytes); ComPort.Write(Ptr^, NumBytes); FreeMem(Ptr); Those are compiler intrinsic functions, they have special handling for parameters that you don't normally get with user-defined functions.
  5. Remy Lebeau

    TTreeview to JSON VCL?

    Duplicate:
  6. Remy Lebeau

    Write process memory

    There is no link (not that it matters, I didn't ask for the code, I asked you to clarify your question). That doesn't clarify anything. My earlier question still stands.
  7. Remy Lebeau

    Write process memory

    I'm not sure what you are asking for exactly. Are you asking for someone to make a GUI frontend for your code? Or, do you want to write to memory of an external GUI program? Writing to a process's memory is the title of this discussion thread, but your code is not attempting to do that. So your question seems to be about something else entirely. Please clarify.
  8. Remy Lebeau

    Creating HTTPS connection with Indy TIdHTTPserver

    As the browser's error message says, your server's certificate doesn't prove that 127.0.0.1 and mycomputer are the same entity, so the browser fails the handshake. Did you try connecting to https://mycomputer:4567 instead? The certificate you have is registered to a hostname, so that hostname must be specified in the URL used to access the server. See: Is it possible to have SSL certificate for IP address, not domain name?
  9. The response is sending you back an HTML page with Javascript on it. Is it possible that the Javascript is manipulating the page in a way that affects the HTTP requests? This goes back to my earlier comments. Stop focusing on the HTML, you need to pay closer attention to the raw HTTP traffic instead. You need to use your browser's built-in debugger to see what requests are actually being sent, and what responses are actually being received. Then you can just replicate those in your code as needed. Until you can get that raw traffic that, I can't help you any further. The POST request is sending back the same cookie that the GET response contained: From GET Response: Set-Cookie: ASPSESSIONIDQWRQBQCS=JM.................CL; secure; path=/ In POST request: Cookie: ASPSESSIONIDQWRQBQCS=JM.............CL The POST response is then sending back a new cookie: Set-Cookie: ASPSESSIONIDQWRQBQCS=MM............BP; secure; path=/ That is perfectly normal and acceptable. It is the same cookie name, just a different value. The server is well within its right to change the value of a cookie between requests. In this case, the cookie contains state information, and clearly that state is changing.
  10. TThread internally checks its Terminated property before calling Execute(). When you destroy a TThread that hasn't finished yet, the TThread destructor calls Terminate() and WaitFor() on itself. So, if you destroy a TThread before it even begins running, Execute() won't be called. That is nothing new, TThread has behaved this way for many years.
  11. Yes, leave the double-quotes off. A space character will be encoded as '%20' during transmission, eg: 'del=my%20delete' Because you didn't send the correct 'del' value, the server script probably didn't understand that you were asking for a delete operation. Again, before you can code the requests properly, you first need to study and understand what a web browser sends for each request. I'm not at a computer right now, so I can't look at that file. I'll have to look at it later.
  12. Remy Lebeau

    Attach to Process along with Stepping through Code

    Then ignore the Remote Debugger and the .rsm file (turn off remote debug symbols). All you need is the .tds file alongside the .exe file.
  13. That should be using X.WaitFor() instead of WaitForSingleObject() directly. var x: TMyThread; begin x := TMyThread.Create(False); try // x.Start; // if suspended... X.WaitFor; finally x.Free; end; end;
  14. You need to remove the double-quotes on the 'del' value, like I showed you eariler. In what way, exactly, does it not work? Please be more specific. It should be sending back the existing cookie, thus being a single session. TIdHTTP and TIdCookieManager handle that automatically for you, if you are reusing the same objects for multiple requests.
  15. I don't use Chrome, so I can't comment on what it does or does not show you. But a GET request does not typically have a request body, which is why I said you should not set the ContentType/CharSet properties when calling TIdHTTP.Get(). Calling TIdHTTP.Post() is a different matter.
  16. Remy Lebeau

    Attach to Process along with Stepping through Code

    Make sure the .tds file and .rsm file are in the same folder as the .exe file. The Remote Debugger is used when the .exe file is run on a different machine than the IDE is run on. In which case, you need to run the Remote Debugger app on the same machine as the .exe file, and then connect the IDE to the Remote Debugger app over the network.
  17. Remy Lebeau

    Windows VCL application pauses when window is not focused...

    You should never have to do that if your main UI thread is running properly. The main UI message loop already handles requests from TThread.Synchronize() and TThread.[Force]Queue() for you. The only time you ever need to call CheckSynchronize() manually is if either you are blocking the main UI message loop, or if there is no message loop at all (such as in a console app).
  18. In TIdHTTP, that would look like this: var PostData: TStringList; begin PostData := TStringList.Create; try PostData.Add('roomid=1'); PostData.Add('topicfatherid=648330'); PostData.Add('topicid=648379'); ... // either: PostData.Add('edit=edit'); // or (depending on which button is clicked): PostData.Add('del=delete'); PostData.Add('topic_title=2'); PostData.Add('topic_content=...'); IdHTTP1.Post('https://<<addres-from-server>>/topic_edit_submit.asp', PostData); finally PostData.Free; end; end; To submit an HTML webform whose 'enctype' attribute is set to 'multipart/form-data'. The default enctype is 'application/x-www-form-urlencoded', which is handled by the TStrings overload of TIdHTTP.Post(), as shown above. No. The most common use of 'multipart/form-data' is when uploading files, or otherwise sending large amounts of data.
  19. Again, simply use your browser's DEBUGGER to see the actual HTTP request that is transmitted to the server when the Delete button is clicked. And then you can replicate that same request with TIdHTTP as needed. Not all requests use URL parameters, typically requests like POST use a request body instead, which you can't see in a URL. I have no idea what you are saying.
  20. Remy Lebeau

    Sending Email via GMail Using OAuth 2.0 via Indy

    What exactly are you having trouble with?
  21. Remy Lebeau

    Sending Email via GMail Using OAuth 2.0 via Indy

    That directive was introduced in XE5.
  22. Remy Lebeau

    TIdHttp - incorrect UTF-8

    You did not say which version of Delphi you are using. If it is Delphi 2009+, then as @aehimself mentioned, you need to specify the correct TEncoding for the TStringStream to use, eg: Req_Json := TStringStream.Create(Json, TEncoding.UTF8); If you are using an older version, then you are responsible for populating the TStringStream (better to use TMemoryStream in that case) with proper UTF-8 data yourself, eg by calling UTF8Encode() (since pre-2009 versions of Delphi did not have a native UTF-8 string type yet). That being said, there are some other issues with your code... You are leaking the TIdSSLIOHandlerSocketOpenSSL object, as you are not assigning an Owner to it, and not Free'ing it. You should assign the TIdHTTP object as its Owner, eg: ssl := TIdSSLIOHandlerSocketOpenSSL.Create(IdHTTP); Also, on these statements: ssl.SSLOptions.Method := sslvTLSv1_2; ssl.SSLOptions.SSLVersions := [sslvTLSv1, sslvTLSv1_1, sslvTLSv1_2]; You DO NOT need to set the Method property, the SSLVersions setter will handle that for you (not to mention, you are setting it to the wrong value, anyway). Also, DO NOT use the TIdHTTP.Request.CustomHeaders property to specify a 'Content-Type' header. Use the TIdHTTP.Request.ContentType property instead: IdHTTP.Request.ContentType := 'application/octet-stream'; But why are you using 'application/octet-stream' instead of 'application/json'? Same notes about the SSL object here, too. Also, why are you creating a TMemoryStream that you are not using for anything? Also, again, which version of Delphi are you using? If you are using a pre-2009 version, the string returned by TIdHTTP.Get() will be the raw bytes of the downloaded data. But in Delphi 2009+, the returned string will be a UTF-16 UnicodeString. DO NOT use AnsiToUtf8() to convert that to UTF-8. Simply assign it to a UTF8String instead, or at least use UTF8Encode(). However, you are assigning the converted result to another native string, which will undo the conversion in D2009+. So, you are best off just displaying the original string as-is, whatever format it is in. That being said, if the downloaded content is UTF-8 to begin with, you are better off downloading it into your TMemoryStream instead of to a string, and then you can copy the content of the TMemoryStream into a UTF8String using SetString(), and display it as-is. Or save the TMemoryStream to a file as-is. Etc.
  23. Since you are asking how to implement this with Indy, you should have posted this in the Indy group: https://en.delphipraxis.net/forum/35-indy/ You don't really have a choice in that matter. This is an all-or-nothing kind of deal. You are basically simulating a web browser, so you are going to receive whatever a web browser would receive to render data onscreen for the user to interact with. What you decide to do with that data is up to you. But if this is not the kind of data you want, then you should check if the website in question offers a separate REST API to access the data in another format that is more machine-oriented rather than user-oriented. You are not sending any data to the server, so you shouldn't be assigning values to those properties at all. And? What is your actual question about them? You are going to have to look at the underlying HTTP requests that a normal web browser submits for those actions, and then replicate them in your code accordingly. Because that is what you are asking for from the server. You are requesting data from a URL of an HTML webpage, so HTML is what you get back. Unless the server explicitly supports that operation for the URL in question (ie, via a URL query parameter or the 'Accept' header, etc), then you won't be able to get what you want. Either find another URL that gives you the data you want in the format you want, or else you will just have to deal with the HTML you are given. Only if the server supports giving out JSON. But, there is no way for anyone here to tell you how to do that, since you haven't even explained which website you are trying to access in the first place. If all you have is HTML, then you are just going to have to parse it to extract what you want from it. You probably don't need step 2 at all. Chances are, you can likely just look at the HTML of the edit webpage to determine the URL that it submits to, and then you can make your code Post() to that same URL with the appropriate headers and data as needed. Again, just look at the HTML for the appropriate webpage, and then have your code post your data to the same URL. Same as above. Determine the URL that the delete webpage submits to, and then make your code post an appropriate request to that same URL. OK, so what is the problem? Most modern web browsers have a built-in debugger that can show the raw HTTP traffic. TIdHTTP is just a wrapper for the HTTP protocol, so see what kind of HTTP requests a web browser sends for the actions you are interested in, and then replicate those requests in your TIdHTTP code. Not that hard, really.
  24. Remy Lebeau

    FTP - Problems sind update to Alexandria

    TIdFTP has a PassiveUseControlHost property for that exact purpose. It is False by default. TIdFTP has a UseExtensionDataPort property to enable use of EPSV if the server supports it. This is also False by default.
  25. Remy Lebeau

    Sending Email via GMail Using OAuth 2.0 via Indy

    Failed how, exactly? Since you are posting this in an Indy forum, I'll give you an Indy answer - You can either turn on 2-Factor Authentication in your Google account and then create an App-Specific password for Indy to use, thus not requiring OAuth2 and no code changes or upgrades needed to use TIdSMTP/TIdPOP3/TIdIMAP4. Or, if you must use OAuth2, then install the latest Indy OAuth2 branch code (https://github.com/IndySockets/Indy/tree/sasl-oauth) into your Delphi 2010 (which Indy still supports), replacing any Indy version you may already have installed (https://github.com/IndySockets/Indy/wiki/Updating-Indy), and then you can use TIdHTTP to retrieve an access token from Google, and use TIdSASLXOAuth2 to use that token with TIdSMTP/TIdPOP3/TIdIMAP4.
×