-
Content Count
3007 -
Joined
-
Last visited
-
Days Won
135
Everything posted by Remy Lebeau
-
Twsocket udp how to get the exact buffersize that received ? ?
Remy Lebeau replied to Skullcode's topic in VCL
That is true for TCP, where there is no 1:1 relationship between sends and reads, it is just a stream of bytes. But that is not true for UDP, where there is a 1:1 relationship, since sends/reads deal only in whole datagrams. A datagram can't span multiple read events, a read operation must read the whole datagram in one go, or else the unread portions will be lost. -
Returning a dynamic array from DLL
Remy Lebeau replied to Tim Chilvers's topic in RTL and Delphi Object Pascal
The 1st parameter of VarArrayCreate() does not take an index and a count, as you are suggesting. It takes lower/upper bounds (indexes) in pairs, one for each dimension of the array. So, specifying [0, 1] will create a 1-dimensional array with indexes from 0 to 1 (thus 2 elements). Whereas [0, 0] will create a 1-dimensional array with indexes from 0 to 0 (thus 1 element). An empty array would be [0, -1], indexes from 0 to -1 (thus 0 elements). Alternatively, if you know all of the array values up front, you can use VarArrayOf() instead of VarArrayCreate(). I have updated my earlier example to show that. -
Returning a dynamic array from DLL
Remy Lebeau replied to Tim Chilvers's topic in RTL and Delphi Object Pascal
Using interfaces is fine, as long as compilers agree to a common ABI for them. Which typically means you need to use COM interfaces if you want non-Delphi/C++Builder compilers to interact with your code. The main reason your GetCategories() function crashed was two-fold: - it did not allocate any memory for its local TArray, thus when it tried to save an interface to the array's 1st element, it was going out of bounds. - it was returning a raw pointer to the interface stored in the local array's 1st element, not the array itself. But either way, that array and all of its elements were getting finalized when the function exited, thus you were returning a dangling pointer to invalid memory. To persist the array behind the function exit, you need to allocate it dynamically, and you need to increment the refcounts of the individual interfaces in the array. Using COM interfaces, you can let (Ole)Variant handle all of that for you, eg: type IProjectItemCategory = interface(IUnknown) ['{840DD036-8F0F-4B0F-97D0-AB76CCC2157B}'] function GetIdString: WideString; ... property IdString: WideString read GetIdString; ... end; IProjectItemWizard = interface(IUnknown) ['{6C65F413-F2E2-4554-8828-1FF10613855B}'] function GetCategory: IProjectItemCategory; safecall; function GetCategories: OleVariant; safecall; ... property Category: IProjectItemCategory read GetCategory; property Categories: OleVariant read GetCategories; ... end; ... function TTestWizard.GetCategory: IProjectItemCategory; safecall; begin Result := ...; end; function TTestWizard.GetCategories: OleVariant; safecall; var LManager: IProjectItemCategoryServices; LCategory: IProjectItemCategory; LArray: Variant; begin LManager := Services as IProjectItemCategoryServices; if LManager <> nil then begin LCategory := LManager.FindCategory('New'); if LCategory <> nil then begin LArray := VarArrayCreate([0..0], varUnknown); LArray[0] := IUnknown(LCategory); // alternatively: // LArray := VarArrayOf([IUnknown(LCategory)]); end; end; Result := LArray; end; procedure TProjectItemDialog.TreeViewFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex); function IsGalleryCategory(const ACategory: IProjectItemCategory; const AIdString: string): Boolean; begin Result := (ACategory <> nil) and (ACategory.IdString = AIdString); end; function IsInGalleryCategories(const ACategories: OleVariant; const AIdString: string): Boolean; var I: Integer; begin Result := False; if VarIsArray(ACategories) then begin for I := VarArrayLowBound(ACategories, 1) to VarArrayHighBound(ACategories, 1) do begin Result := IsGalleryCategory(IUnknown(ACategories[I]) as IProjectItemCategory, AIdString); if Result then Exit; end; end; end; var LData: PCategoryNodeData; LServices: IWizardServices; LCount, I: Integer; LCategoryCount: Integer; LWizard: IProjectItemWizard; LCategory: IProjectItemCategory; LCategories: OleVariant; begin WizardControlList.ItemCount := 0; try FWizardList.Clear; LData := GetNodeData(Node); if LData <> nil then begin LServices := Services as IWizardServices; if LServices <> nil then begin for LCount := 0 to LServices.WizardCount - 1 do begin if Supports(LServices.Wizard[LCount], IProjectItemWizard, LWizard) then begin LCategory := LWizard.Category; LCategories := LWizard.GetCategories; if IsGalleryCategory(LCategory, LData.Id) or IsInGalleryCategories(LCategories, LData.Id) then begin FWizardList.Add(LWizard); end; end; end; end; end; finally WizardControlList.ItemCount := FWizardList.Count; end; end; -
Twsocket udp how to get the exact buffersize that received ? ?
Remy Lebeau replied to Skullcode's topic in VCL
Another option would be to peek the socket first to query the size of the next available datagram without reading it, then allocate the buffer to that size, then read the datagram into the buffer. But a dynamic array of raw bytes is trivial to shrink in size, so over-allocating a little is not a bad thing (unless you are running in an embedded system). -
How to Convert curl command line to Delphi code using IndyHttp or THttpClient.
Remy Lebeau replied to amit's topic in Network, Cloud and Web
Probably due to this feature: https://www.indyproject.org/2014/12/22/new-https-functionality-for-tidhttp/ You MUST use an SSLIOHandler if you want to access an HTTPS url. Whether you create your own SSLIOHandler object, or let TIdHTTP create one implicitly, is a separate matter. -
Shutting down TidTCPServer (kbmMWTCPIPIndyServerTransport)causing Window Service timeout
Remy Lebeau replied to c0d3r's topic in Indy
Again, there is really nothing I cn do to help you without seeing you actual TCP server code. You clearly have a logic issue somewhere, but I can't see what you are doing with it. That workaround only minimizes the issue, but does not eliminate it. There could still be clients connected when the service is being shut down, and it only takes 1 misbehaving client/thread to cause the problem. Very little, since Embarcadero had incorporated the latest GitHub version (at the time) shortly before Sydney's release. There have been a number of checkins to GitHub since that time, but nothing that would address this particular issue. -
How to Convert curl command line to Delphi code using IndyHttp or THttpClient.
Remy Lebeau replied to amit's topic in Network, Cloud and Web
The TIdHTTP version would look like this: uses ..., IdHTTP, IdSSLOpenSSL, IdMultipartFormDataStream; var HTTP: TIdHTTP; SSL: TIdSSLIOHandlerSocketOpenSSL; Params: TIdMultipartFormDataStream; begin HTTP := TIdHTTP.Create; try SSL := TIdSSLIOHandlerSocketOpenSSL.Create(HTTP); SSL.SSLOptions.SSLVersions := [sslvTLSv1, sslvTLSv1_1, sslvTLSv1_2]; // other options as needed... HTTP.IOHandler := SSL; HTTP.Request.BasicAuthentication := False; HTTP.Request.CustomHeaders.Values['Authorization'] := 'Bearer U4314taadsffhjjjjykllFVissffdfssdfsdfsgfgz'; // or: HTTP.Request.CustomHeaders.AddValue('Authorization', 'Bearer U4314taadsffhjjjjykllFVissffdfssdfsdfsgfgz'); Params := TIdMultipartFormDataStream.Create; try Params.AddFormField('message', 'abcTest'); Params.AddFormField('stickerPackageId', '1'); Params.AddFormField('stickerId', '113'); Params.AddFile('imageFile', 'D:\mypic.jpg'); HTTP.Post('https://notify-api.line.me/api/notify', Params); finally Params.Free; end; finally HTTP.Free; end; end; -
A LONG time ago (9 years!), I posted a demo on StackOverflow for displaying an alpha-blended TForm as a dimming shadow over top of another TForm, while allowing individual controls to remain uncovered and interactive through the shadow: How do I put a semi transparent layer on my form Basically, the shadow TForm uses its AlphaBlend/Value properties to provide the dimming effect, and its TransparentColor/Value properties to mask out holes in the shadow where individual controls want to peek through. I'm sure a similar technique can be adapted for this situation.
-
Do note that solution is applying the WS_EX_LAYERED window style to a child window, which is supported only in Windows 8 onwards, and only if the app manifest specifies Windows 8 as a <supportedOS>.
-
Makes sense. You didn't put TCustDBGrid into a package and install it into the IDE, so you can't use TCustDBGrid in a DFM resource, unless you call RegisterClass(TCustDBGrid) before the DFM is loaded when the TForm object is created. Because you are trying to actually call TForm1's inherited MouseDown() method and then assign its result to the event. Use this instead: unit Unit1; interface uses ..., Vcl.DBGrid, ...; type TDBGrid = class(Vcl.DBGrid.TDBGrid) protected procedure MouseDown(Sender: TObject; Button: TMouseButton; ShiftState: TShiftState; X, Y: Integer); override; end; TForm1 = class(TForm) ... recentinfo: TDBGrid; .. end; implementation procedure TDBGrid.MouseDown(Sender: TObject; Button: TMouseButton; ShiftState: TShiftState; X, Y: integer); begin if Button = mbRight then ShowMessage("testing"); inherited; end; No, because you are not registering the TCustDBGrid class with the DFM streaming system.
-
Range Check Error ERangeError
Remy Lebeau replied to david_navigator's topic in RTL and Delphi Object Pascal
32bit vs 64bit? You really should not be casting to Integer at all. Cast to WPARAM instead, which is what PostMessage() is expecting procedure TEqlistFrm.VenueEditMainKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin PostMessage(Handle, CM_SEARCH, WPARAM(Sender), LPARAM(Key)); end; -
See https://hero.handmade.network/forums/code-discussion/t/7485-queryperformancefrequency_returning_10mhz_bug Also of interest, see MSDN: https://docs.microsoft.com/en-us/windows/win32/sysinfo/acquiring-high-resolution-time-stamps
-
How to create an object instance from its class name?
Remy Lebeau replied to Incus J's topic in RTL and Delphi Object Pascal
It can be passed in as a normal parameter, and even used in ClassType comparisons, but it can't be used for type-casts, eg: function CreateAnObjectByClassName(const ClassName: string; BaseClass: TPersistentClass): TPersistent; var Cls: TPersistentClass; begin Cls := GetClass(ClassName); if not Cls.InheritsFrom(BaseClass) then raise Exception.Create('...'); Result := BaseClass(Cls).Create; // <-- doesn't work end; The compiler needs to know the actual class type that exposes the necessary constructor in order to call it directly. Otherwise, you have to resort to using RTTI to call the constructor, as demonstrated in the code Stefan linked to. There are alternative ways to accomplish that, just not as clean as what you are thinking. -
How to create an object instance from its class name?
Remy Lebeau replied to Incus J's topic in RTL and Delphi Object Pascal
That is because neither TObject, TPersistent, nor TInterfacedObject have a virtual constructor that your descendants can override. The lowest RTL class that introduces a virtual constructor is TComponent. You need to add a virtual constructor to TMyClass and have desccendants override it as needed. And then declare your own metaclass type for your creation function to use. For example: type TMyClass = class(TInterfacedPersistent, IMyInterface) public constructor Create; virtual; end; TMyClassType = class of TMyClass; function CreateAnObjectByClassName(const AClassName: string): TPersistent; begin Result := TMyClassType(GetClass(AClassName)).Create; end; ... type TMyClass1 = class(TMyClass) public constructor Create; override; end; TMyClass2 = class(TMyClass) public constructor Create; override; end; RegisterClasses([TMyClass1, TMyClass2, ...]); -
Private class members raise an exception in 10.4.2 when I try to use RTTI on them
Remy Lebeau replied to Andrea Raimondi's topic in RTL and Delphi Object Pascal
Nope. There is no method of TRttiContext that takes an object instance as input. FindType() takes in a class type as a string, and GetType() takes in a class type as a TClass or PTypeInfo. -
In what way exactly? Rather than someone translating your TIdHTTP code, can you show your existing TNetHTTPRequest code that is not working for you?
-
https://github.com/IndySockets/OpenSSL-Binaries https://www.indyproject.org/2020/06/16/openssl-binaries-moved-to-github/
-
The code shown is not the correct logic to parse an RFC2047-encoded string. Try something more like the instead (though this could be simplified using IdGlobal.Fetch(), for instance): uses IdGlobal, IdGobalProtocols, IdCoderMIME, idCoderQuotedPrintable; procedure TForm1.convertbuttonclick(Sender: TObject); var s, s2, charset, encoding, data : string; i, j: Integer; begin s := Memo1.Lines[0]; s2 := s; i := Pos('=?', s); if i > 0 then begin Inc(i, 2); j := Pos('?', s, i); if j > 0 then begin charset := Copy(s, i, j-i); i := j+1; j := Pos('?', s, i); if j > 0 then begin encoding := Copy(s, i, j-i); i := j + 1; j := Pos('?=', s, i); if j > 0 then begin data := Copy(s, i, j-i); if TextIsSame(encoding, 'B') then s2 := idDecoderMIME.DecodeString(data, CharsetToEncoding(charset)) else if TextIsSame(encoding, 'Q') then s2 := idDecoderQuotedPrintable1.DecodeString(data, CharsetToEncoding(charset)); end; end; end; end; Memo2.Lines.Clear; Memo2.Lines.Add(s2); end; That being said, Indy already implements a decoder for RFC2047-encoded strings, in the DecodeHeader() function of the IdCoderHeader unit, eg: uses IdCoderHeader; procedure TForm1.convertbuttonclick(Sender: TObject); var s, s2 : string; begin s := Memo1.Lines[0]; // '=?UTF-8?B?5aaC5L2V6K6TIGFydC1tYXRlIOaIkOeCug==?=' s2 := DecodeHeader(s); Memo2.Text := s2; end;
-
It is hard to diagnose your issue without seeing the raw email data, and/or your code that is creating the email, and even knowing which version of which Pascal compiler you are using (Delphi vs FreePascal), since string handling varies by compiler and even by version. I can't answer that with the limited details you have provided so far. For instance, if you are using a Unicode version of Delphi (2009+ or later) or FreePascal (3.0+ with UnicodeStrings enabled), then yes, it should be converting to UTF-8 property. But if you are using a pre-Unicode version of Delphi/FreePasscal, then no, it will not convert to UTF-8 automatically, so you are responsible for encoding your own strings to UTF-8 before giving them to Indy. What does your actual text look like? This score implies that you have a lot of script changes happening inside of individual words. Which might just be a side effect of UTF-8 not being encoded properly. Hard to say without seeing the raw data. What do you have the TIdMessage.Encoding property set to? It is set to meDefault by default, which will be auto-updated to either mePlainText or meMIME depending on whether the TIdMessage.MessageParts collection is empty or not, respectively. A 'MIME-Version' header is generated only when TIdMessage.Encoding is meMIME. In general, you don't need to use MIME if your email contains only plain text, but it sounds like the provider may be requiring MIME. So, you may need to force the TIdMessage.Encoding to meMIME. UTF-8 is an 8-bit encoding, so it requires a transfer encoding that supports 8-bit data. '7bit' will truncate/zero the high bit of each byte, thus corrupting non-ASCII characters. So, you need to set the TIdMessage.ContentTransferEncoding property (and the TIdMessagePart.ContentTransfer property in entries of the TIdMessage.MessageParts collection) to either '8bit', 'base64', or 'quoted-printable' when using UTF-8 text to avoid any potential data loss. Note that '8bit' emails do require additional support from an SMTP server (features which Indy does not currently implement), so use 'base64' or 'quoted-printable', which are compatible with 7-bit systems. If the text is mostly ASCII characters, I would use 'quoted-printable'. If the text is mostly non-ASCII characters, I would use 'base64' instead.
-
Then you likely did not create the file where you are expecting. Are you using relative paths, for instance? What is the actual value of your fn variable? The filesystem does not lie about file existence. If it says a file does not exist, then it really does not exist. Double-check your input. With the same ERROR_FILE_NOT_FOUND error? I suggest you use SysInternals Process Monitor to see EXACTLY which file path your app is REALLY trying to access, and make sure it matches your expectation.
-
Then you likely don't have access to the file, or at least don't have permissions to ask the filesystem for its attributes. You need to call GetLastError() to find out why GetFileAttributes() is failing.
-
GetFileAttributes() can return INVALID_FILE_ATTRIBUTES for a number of different reasons, not just because the file does not exist. You have to use GetLastError() to differentiate the actual cause.
-
IdHttp not connect IP Camera error 401
Remy Lebeau replied to Marcio's topic in Network, Cloud and Web
I suggested EITHER approach, not BOTH. Use either BASIC or DIGEST. Did you verify that TIdHTTP is actually trying to send BASIC/DIGEST authentication in its request? I'm guessing either you are not setting the TIdHTTP.Request.Username/Password correctly (are you ABSOLUTELY SURE you are using the correct credentials? Are there any non-ASCII characters present in them?), or the camera is not accepting Indy's flavor of DIGEST authentication (BASIC is very, well, basic and difficult to get wrong). Can you provide an example showing the raw HTTP messages from start to end? -
after updating to windows 20h2 i can't register bcb 6 anymore
Remy Lebeau replied to JeanCremers's topic in General Help
Until a few months ago, I also depended on BCB6 for my full-time job (my software has reached its End-Of-Life, so this is no longer an issue), but in the past 15-odd years, moving it into a VM was never really an option. The physical machine it ran in was over 500GB of logs, databases, backups, etc, so cloning it would have taken forever. But more importantly, it had specialized PCI hardware installed that didn't work inside a VM, and I never had the time to create a new VM with just BCB6 installed. I would have had to continue running my apps on the physical machine, but used the remote debugger inside a VM, and I wasn't too keen on that approach, either, -
IdHttp not connect IP Camera error 401
Remy Lebeau replied to Marcio's topic in Network, Cloud and Web
Your camera supports BASIC and DIGEST authentications. By default, TIdHTTP enables only BASIC authentication, which you are explicitly disabling by setting the TIdHTTP.Request.BasicAuthorization property to False. You need to either: re-enable BASIC authentication by setting TIdHTTP.Request.BasicAuthorization to True. enable DIGEST authentication by adding the IdAuthenticationDigest, or IdAllAuthentications, unit to your Form's uses clause.