-
Content Count
2684 -
Joined
-
Last visited
-
Days Won
113
Everything posted by Remy Lebeau
-
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).
-
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.
-
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?
-
It does unchunk a chunked response, yes. It does not send chunked requests, though.
-
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.
-
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;
-
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().
-
You can't send window messages to a non-windowed class. Well, unless you are calling TObject.Dispatch() directly, that is. Are you? Why are you not posting (not sending) the message to an actual window? You did not show how you are actually sending the message to the class in the first place. Yes, it should, if the messages are going through the normal Dispatch() mechanism to begin with. But since you didn't show your actual code, maybe that is not actually the case? We can't see your code. 144 is in the range of system-reserved message IDs, however there is no known system message with an ID of 144. Message ID 2 is WM_DESTROY, though.
-
Yup, it is not working again for me, too.
-
It is working for me.
-
I think if you change StartQuote to '<div class="q-te"><span>', you should be OK. At least, until the next time the website decides to change formats. This is why scraping data from webpages is not a good idea. It is cumbersome and unreliable over time. It would be better if you can find a different feed that provides data in a machine-parsable format like XML or JSON instead, then you don't run into these kind of issues.
-
But, you haven't explained WHY it is not working. Are you getting errors? Are you not getting the data you are expecting? Be SPECIFIC. Have you tried to debug the code at all? Does TIdHTTP.Get() complete without exception? What are StartQuote and EndQuote defined as?
-
I never liked McAfree.
-
I see some language-related issues in the code, but nothing that I would consider to be a "problem" with Indy itself. You are creating the TIdHTTP object before the try..except block, instead of inside of it. The 'if E.ClassName = 'EIdConnClosedGracefully'' statement should be using the 'is' operator instead: if E is EIdConnClosedGracefully then Or better, using separate 'on' clauses in your 'except' block: except on E: EIdConnClosedGracefully do begin // ShowMessage('Unable to access Thought for the Day at this time.'); // EXIT; end; on E: Exception do begin // ShowMessage('Exception class name = ' + E.ClassName); ShowMessage('Exception message = ' + E.message); // end; // end; And you should use a proper HTML parser instead of what you have now. Why not? What is the ACTUAL PROBLEM you are having? Please be more specific. Just saying it "doesn't work" is meaningless.
-
How to save send SMTP mail to .eml file
Remy Lebeau replied to Helge Larsen's topic in ICS - Internet Component Suite
Indy (more specifically, its OpenSSL IOHandler) supports TLS 1.2 just fine, so you should not have needed to switch to another SMTP library just to continue communicating with Microsoft. -
In addition to everthing said about AddRef/Release(), just note that if your Form's window is ever recreated at runtime, you will loose your marking and have to re-apply it on the new window. Best way to avoid that is to have your Form class override the virtual CreateWnd() method to call MarkWindowAsUnpinnable(), don't call it after creating the Form object.
-
This is why you should configure your AntiVirus/AntiMalware to ignore compiler output folders as exceptions.
-
Yes, you can. You can see the RTL doing exactly that, for instance in the SysUtils.(Wide)FormatBuf() functions. Yes. Yes. Just know that if the AnsiString is empty, the pointer will be nil, so don't dereference it. I prefer to use this instead: Move(PAnsiChar(AnsiString(VAnsiString))^, If the AnsiString is empty (ie, a nil pointer), the PAnsiChar cast will return a non-nil pointer to a #0 AnsiChar in static memory. So the dereference is always valid. Also, this isn't affected by 0-based vs 1-based string indexing. Yes.
-
What is 'S' in this code? It appears to be a pointer into an array of AnsiChars. The code appears to be building up an inline array of length-prefixed ANSI strings. Maybe for transmission/storage somewhere? In any case... vtString indicates a ShortString. Since ShortString is a fixed-length string, the TVarRec.VString field is a pointer to an actual ShortString variable. The code is handling the VString field correctly, dereferencing that pointer to access the ShortString, and thus its length and characters. vtAnsiString indicates an AnsiString. An AnsiString is a dynamic length string, and an AnsiString variable is just a pointer to the AnsiString's payload. As such, the TVarRec.VAnsiString field is a pointer to an AnsiString's payload, NOT a pointer to an AnsiString variable. The code is not handling the VAnsiString field correctly, most importantly its use of sizeof() is wrong to determine the AnsiString's length. You need to typecast the VAnsiString pointer to an AnsiString and then query its Length() instead. Try this: var Len: Integer; ... for I := Low(Values) to High(Values) do with Values[I] do case VType of vtString: begin Len := Length(VString^); // will never exceed 255 S[P] := AnsiChar(Len); System.Move(VString^[1], S[P+1], Len); Inc(P, Len + 1); ls := I = High(Values); end; vtAnsiString: begin Len := Length(AnsiString(VAnsiString)); if Len > 255 raise ...; S[P] := AnsiChar(Len); System.Move(PAnsiChar(AnsiString(VAnsiString))^, S[P+1], Len); Inc(P, Len + 1); ls := I = High(Values); end; ... end; WideString and UnicodeString are also dynamic length string types implemented as pointers, and so vtWideString and vtUnicodeString are handled similarly to vtAnsiString, in that you simply type-cast the TVarRec.VWideString and TVarRec.VUnicodeString pointers as-is to WideString and UnicodeString, respectively. Just know that you will need an additional cast to AnsiString for those values to fit in with the rest of this code, eg: var Len: Integer; Tmp: AnsiString; ... for I := Low(Values) to High(Values) do with Values[I] do case VType of ... vtWideString: begin Tmp := AnsiString(WideString(VWideString)); Len := Length(Tmp); if Len > 255 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 Len > 255 raise ...; S[P] := AnsiChar(Len); System.Move(PAnsiChar(Tmp)^, S[P+1], Len); Inc(P, Len + 1); ls := I = High(Values); end; ... end;
-
Async await with blocking mode using Application.ProcessMessage(var Msg: TMsg)
Remy Lebeau replied to Nasreddine's topic in VCL
That is what the "Msg" in its name stands for - it can wait on the Message Queue AND on a list of signallable objects. SyncEvent is used to let the main thread know when TThread.Synchronize()/TThread.Queue() requests are pending. It is not used to let the main thread know when messages are pending. Simply call MsgWaitForMultipleObjects() with any of the flags that wait on the message queue (I usually just use QS_ALLINPUT), and then call Application.ProcessMessages() whenever MsgWaitForMultipleObjects() reports that messages are pending (when its return value is WAIT_OBJECT_0 + nCount). -
Async await with blocking mode using Application.ProcessMessage(var Msg: TMsg)
Remy Lebeau replied to Nasreddine's topic in VCL
Not if you pump the message queue whenever MsgWaitForMultipleObjects() tells you that messages are waiting. -
Pascal syntax highlighter treats backslash as escape character
Remy Lebeau posted a topic in Community Management
Something that has been annoying me for awhile. When posting a code snippet and choosing the Pascal syntax highlighter, backslashes are treated as C/C++ escape sequences, which throws off the coloring. The actual Pascal language doesn't treat backslash as an escape character. Can this be fixed? -
Can you be more specific? What is the ACTUAL problem? That is a LOT of code for a seemingly simple problem. Can you narrow it down to a much simpler test case?
-
Good point. I have removed that suggestion.
-
Pascal syntax highlighter treats backslash as escape character
Remy Lebeau replied to Remy Lebeau's topic in Community Management