-
Content Count
2684 -
Joined
-
Last visited
-
Days Won
113
Everything posted by Remy Lebeau
-
I have just now fixed the two issues you mentioned: https://github.com/IndySockets/Indy/issues/456
-
I'm a professional developer who worked for a company that used C++Builder (almost) exclusively for almost 20 years.
-
Why does CoInitializeEx returns 1 or $80010106 ?
Remy Lebeau replied to maXcomX's topic in Windows API
Aggregating the FTM means your COM object would need to call the CoCreateFreeThreadedMarshaler() function and save the IUnknown interface it gives you, and then have your object's QueryInterface() method return that interface when it is asked for IID_IMarshal. However, nothing in the ActivateAudioInterfaceAsync() documentation mentions aggregating the FTM at all. All it says is that your completionHandler object needs to implement the IAgileObject interface, nothing more. IAgileObject is an indicator that lets the system know that the object is free-threaded and thus can be called across apartment boundaries without marshaling. You DO NOT need to implement TAggregatedObject in this situation. TAggregatedObject and IAgileObject are completely different and related things. Right, because you did not hook up the TAggregatedObject.Controller to point at another COM object. As you can see in the code snippet you posted, TAggregatedObject.QueryInterface() simply delegates to another COM object. Correct. Yes. You would need something like this: TActivateAudioInterfaceCompletionHandler = class(TInterfacedObject, IActivateAudioInterfaceCompletionHandler, IAgileObject) public function ActivateCompleted(activateOperation: IActivateAudioInterfaceAsyncOperation): HRESULT; stdcall; end; function TActivateAudioInterfaceCompletionHandler.ActivateCompleted(activateOperation: IActivateAudioInterfaceAsyncOperation): HRESULT; stdcall; begin // do something... end; ... ActivateAudioInterfaceAsync( ..., TActivateAudioInterfaceCompletionHandler.Create as IActivateAudioInterfaceCompletionHandler, ... ); -
https://docwiki.embarcadero.com/RADStudio/en/Parameters_(Delphi)#Untyped_Parameters Yes. No. It would not return anything at all, because the parameter is being passed in by value, not by var reference. So, it is essentially just a local variable that is a copy of the caller's variable. As such, you are just assigning the object to a local variable, and the caller's variable is left untouched. The object's refcount will be incremented when the local variable is assigned to, and then be decremented when the local variable goes out of scope. The caller will never see the object at all. It is not the object itself that goes out of scope, just the interface variable that refers to the object. But no, the variable is not assigned nil, it is already out of scope, its value doesn't matter anymore. But, when the variable does go out of scope, if it has a non-nil value then the refcount of the object it is referring to will be decremented. The object is automatically destroyed only when its refcount falls to 0. Never call Free() on an interfaced object. Use reference counting instead. And, there is no FreeAndNil() member method, only a standalone function. So SomeObject.FreeAndNil() is not valid, only FreeAndNil(SomeObject) is valid. And, it is only valid on an object variable, not an interface variable. In any case, if you need an interface variable, that has not gone out of scope yet, to be set to nil automatically when the object it refers to is destroyed, you need to declare the interface variable as [weak].
-
It depends. You did not show the actual declaration and implementation of CreateAndReturnAnObject(), so it is possible that it could go either way. For instance, if the parameter is an untyped var, then the created object WILL NOT have its reference count incremented when assigned to the parameter, and so the object will die (or worse, be leaked) when CreateAndReturnAnObject() exits: function TSomeclass.CreateAndReturnAnObject(var MyObject): Boolean; begin MyObject := TMyInterface.Create; // <-- refcount IS NOT incremented! Result := True; end; To solve that, you would need to use an explicit type-cast: function TSomeclass.CreateAndReturnAnObject(var MyObject): Boolean; begin IMyInterface(MyObject) := TMyInterface.Create; // <-- refcount IS incremented! Result := True; end; // Or: function TSomeclass.CreateAndReturnAnObject(var MyObject): Boolean; begin MyObject := TMyInterface.Create as IMyInterface; // <-- refcount IS incremented! Result := True; end; Or, call _AddRef() directly: function TSomeclass.CreateAndReturnAnObject(var MyObject): Boolean; var Intf: IMyInterface; begin Intf := TMyInterface.Create; // <-- refcount IS incremented here MyObject := Intf; Intf._AddRef; // <-- refcount is incremented again Result := True; end; // <-- refcount is decremented here On the other hand, if the parameter is typed as a var reference to IMyInterface, then the reference count WILL be incremented as expected: function TSomeclass.CreateAndReturnAnObject(var MyObject: IMyInterface): Boolean; begin MyObject := TMyInterface.Create; // <-- refcount IS incremented! Result := True; end; The calling code you have shown would compile in both cases (once you drop the var at the call site, see below), so it is important to know what the parameter is actually typed as to begin with. Specifying var when passing a variable to a function parameter is not valid syntax to begin with. You can use var only when declaring a variable/parameter, but not when passing it around. Pascal is not C#, or other languages, that require you to be explicit about how a variable is passed to a function parameter. It WILL be auto-incremented when it is assigned to a variable/parameter of a valid interface type.
-
I didn't have any issue with the PACKAGE being named sgcIndy, that is clearly a custom name that is different than Indy's own packages. My only issue was with your WEBSITE ADVERTISING your package as just "Indy" instead of as "sgcIndy".
-
Blocking the app does not require blocking the UI thread. Your code should not sit there blocking the main UI thread waiting until the worker thread ends. Let the code in the UI thread return control back to the VCL's main message loop. Have the thread notify your code when it has finished its work. Simply prevent the user from interacting with your UI in the meantime, if that is what you need to do. Both of the solutions presented to you above will accomplish that for you. You should read the following article: Modality, part 1: UI-modality vs code-modality It is written from the perspective of the Win32 API, but since the VCL is based on Win32, the same concept applies in this case. That requires message handling. Of course, you will get that with an Application.ProcessMessages() loop, but that opens up your code to a host of issues, which have already been pointed out earlier. If you are going to process messages anyway, you may as well let the VCL do it for you. Don't block your UI thread.
-
Why does CoInitializeEx returns 1 or $80010106 ?
Remy Lebeau replied to maXcomX's topic in Windows API
Unfortunately, as I already pointed out earlier, the VCL's TApplication constructor calls OleInitialize() before the ComObj unit has a chance to call CoInitialize/Ex(), and OleInitialize() internally calls CoInitialize(nil), so if you require CoInitializeEx() with any mode other than COINIT_APARTMENTTHREADED then you will have to do your COM work in a separate worker thread instead of in the UI thread. The ComObj unit is not the only unit that uses InitProc. InitProc is a chained list of initialization procedures, so you can't use Assigned(InitProc) alone as an indicator of whether you should call CoInitializeEx() or not. If you need CoInitializeEx() called, then just call it yourself unconditionally, and just be sure to pay attention to whether it fails or not. Returning S_FALSE is NOT a failure condition! A thread cannot change its COM threading mode once it has been set. That is what the RPC_E_CHANGED_MODE error code tells you. That IS a failure condition! If you need to use a different COM threading model than the calling thread has already been set to, you will have to move your COM work to another thread that is able to be set to the desired COM model. Typically, but not necessarily always. It really depends on each app's particular requirements. -
In that kind of example, I would probably opt to use the TThread.OnTerminate event instead, eg: type TMainForm = class(TForm) private ProcessingThread: TThread; procedure EnableUI; procedure DisableUI; procedure ThreadFinished(Sender: TObject); procedure ThreadTerminated(Sender: TObject); ... end; procedure TMainForm.BtnClick(Sender: TObject); begin if Assigned(ProcessingThread) then Exit; DisableUI; try ProcessingThread := TThread.CreateAnonymousThread( procedure begin // do work here end ); ProcessingThread.OnTerminate := ThreadFinished; try ProcessingThread.Start; except FreeAndNil(ProcessingThread); raise; end; except EnableUI; end; end; procedure TMainForm.ThreadFinished(Sender: TObject); begin ProcessingThread := nil; EnableUI; end; procedure TMainForm.ThreadTerminated(Sender: TObject); begin ProcessingThread := nil; Close; end; procedure TMainForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean); begin CanClose := not Assigned(ProcessingThread); if not CanClose then begin ProcessingThread.OnTerminate := ThreadTerminated; ProcessingThread.Terminate; // display a "Please wait" UI ... end; end;
-
SSL not found when using idHttp in docker image
Remy Lebeau replied to Die Holländer's topic in Indy
When loading OpenSSL, Indy checks for a whole list of different filenames, including the 4 you have shown above. The order in which that list is attempted can be influenced by setting Indy's CanLoadSymLinks and LoadSymLinksFirst settings before the libs are loaded. By default, it will attempt to load the unversioned files first, so if that is problematic (because they map to a newer unsupported version of OpenSSL) then you should turn off the CanLoadSymLinks or LoadSymLinksFirst setting so the version-specific libs are attempted first/solely. There are public IdOpenSSLSetCanLoadSymLinks() and IdOpenSSLSetLoadSymLinksFirst() functions in the IdSSLOpenSSLHeaders unit for that purpose. See https://www.indyproject.org/2018/05/04/changes-for-how-openssl-is-loaded-on-nix-platforms/ -
SSL not found when using idHttp in docker image
Remy Lebeau replied to Die Holländer's topic in Indy
What does Indy's IdSSLOpenSSLHeaders.WhichFailedToLoad() function return after the error has occurred? Indy's default TIdSSLIOHandlerSocketOpenSSL component supports up to OpenSSL 1.0.2, it cannot use OpenSSL 1.1.x+, so you need to use this work-in-progress SSLIOHandler instead for newer OpenSSL versions. -
You are probably thinking of the TIdTCPStream class. You can assign a target TIdTCPConnection to it, and then pass it to the IOHandler.ReadStream() method of a source TIdTCPConnection. You can then tell ReadStream() to either read a specific number of bytes, or to read endlessly until the source socket disconnects. Any bytes read in from the source will be written out to the target.
-
Why does CoInitializeEx returns 1 or $80010106 ?
Remy Lebeau replied to maXcomX's topic in Windows API
Can you be more specific? -
Why does CoInitializeEx returns 1 or $80010106 ?
Remy Lebeau replied to maXcomX's topic in Windows API
Per https://stackoverflow.com/a/20019023/65863: And also: https://learn.microsoft.com/en-us/windows/win32/api/ole2/nf-ole2-oleinitialize So, there you go. If your project uses the ComObj unit, it will call CoInitialize/Ex() when Vcl.Forms.TApplication.Initialize() is called, which won't matter since the constructor of Vcl.Forms.TApplication will have already called OleInitialize() beforehand, which calls CoInitializeEx(): constructor TApplication.Create(AOwner: TComponent); var ... begin inherited Create(AOwner); if not IsLibrary then FNeedToUninitialize := Succeeded(OleInitialize(nil)); ... end; -
Why does CoInitializeEx returns 1 or $80010106 ?
Remy Lebeau replied to maXcomX's topic in Windows API
That is S_FALSE. That is RPC_E_CHANGED_MODE. Per the documentation: https://learn.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-coinitializeex This means that you are calling CoInitializeEx() on a thread that has already called CoInitialize/Ex() successfully, where S_FALSE means you are trying to set the same concurrency model that has already been assigned to the thread, whereas RPC_E_CHANGED_MODE means you are specifying a concurrency model that is not compatible with the thread's current concurrency model. For instance, are you calling CoInitializeEx() in the main UI thread? The RTL's System.Win.ComObj unit initializes COM in the main UI thread during program startup, using the global CoInitFlags variable to decide whether to use CoInitialize() or CoInitializeEx(). -
1 is S_FALSE. Per the documentation: https://learn.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-coinitializeex This means that you are calling CoInitializeEx() on a thread that has already called CoInitialize/Ex() successfully, and you are specifying the same concurrency model that has already been assigned to the thread. For instance, are you calling CoInitializeEx() in the main UI thread? The RTL's System.Win.ComObj unit initializes COM in the main UI thread during program startup, using the global CoInitFlags variable to decide whether to use CoInitialize() or CoInitializeEx().
-
Best way to embed a binary structure so it is linked/compiled in
Remy Lebeau replied to alank2's topic in General Help
Put the raw data into a separate binary file, and then add an .rc script to your project (or use the Resources and Images dialog) to compile the data file as an RCDATA resource in your final executable's resources. Then, in your code, you can use a TResourceStream whenever you want to access the resource data at runtime. See Resource Files Support (just ignore the part about using a Multi-Device project, this works in a VCL project, too). -
No recent updates, still pending review: https://github.com/indySockets/indy/pull/299 Correct. It is just built on top of Indy. Their website says: https://www.esegece.com/products/indy/features-overview I agree. As already pointed out, Indy's license does allow them to sell their derivative work. However, I don't like that their website is advertising their product as "Indy", it really should be advertised as "sgcIndy" instead. @esegece I would really appreciate it if you changed the product naming on your website accordingly, and actually explain on it what your product actually is. It is not Indy itself, it is a modification/addon to Indy. Also, your "Quick Start" guide suggests that you have made custom modifications to Indy's default OpenSSL SSLIOHandler, rather than introducing a new SSLIOHandler, as the pending pull request is doing. I would be interested in knowing what kind of modifications you have made to enable that in the default SSLIOHandler, given the extensive and breaking API changes that were introduced in OpenSSL 1.1.x.
-
Can to elaborate more?
-
Beginner to Delphi. Have no idea what I'm doing wrong here
Remy Lebeau replied to Willicious's topic in Delphi IDE and APIs
You forgot to add an OnKeyUp event handler to reset the direction. procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin case Key of Ord('W'): fdirection := diup; Ord('A'): fDirection := diLeft; Ord('D'): fDirection := diRight; Ord('X'): fDirection := diDown; end; end; procedure TForm1.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); begin case Key of Ord('W'), Ord('A'), Ord('D'), Ord('X'): fDirection := diNone; end; end; -
Protected TCP/IP Client/Server connection
Remy Lebeau replied to shineworld's topic in Network, Cloud and Web
That is exactly what TLS is meant for. It handles ALL of that stuff for you. Clients can validate that they are connected to the official server and not another server (especially a man-in-the-middle). And the server can validate that only trusted clients are connecting to it. And ALL communication is encrypted back and forth. -
OpenSSL is an external 3rd party library written in C, so of course it can't use a Delphi unit. Also, OpenSSL uses 2 lib binaries that are LINKED together when they are compiled, the filenames are not hard-coded in code, they are established during the compile/link stages (ie, 1 lib statically imports functions from the other lib), hence why you would have to recompile OpenSSL in order to change its lib filenames.
-
Create() is just a class constructor. In runs in the context of whatever thread calls it, like any other class method. And it does not create any OS window, that happens later. For VCL, all TWinControl-derived UI controls have their own window handle that is created by calling into the OS, and all TGraphicControl-derived UI controls use their parent TWinControl's window. The creation of that window happens in the context of whatever thread is first to access the window. IOW the control creates its OS window on an as-needed basis. However, once it has been created, it is bound to the thread context that created it. There is no OS thread transferring ownership to a Delphi thread. So, for example, if you create a VCL UI control in the context of the main thread, but the first use of its window is in the context of a worker thread, then the window is bound to the worker thread, not to the main thread. As such, only the worker thread can receive and dispatch messages for the window, even though the Delphi object that owns the window is in the main thread. For FMX, by default child UI controls do not have their own OS windows at all, only the parent TForm has an OS window. Child UI controls are designed to act upon, and render themselves inside of, the parent Form's window. However, this is complicated in recent Delphi versions by the introduction of the ControlType property on various controls, like TEdit. In which case, it is possible for some child UI controls to have a native OS window of their own, which runs on top of the parent Form's window, similar to VCL controls.
-
That would require recompiling the OpenSSL libs so could can still find each other using the new filenames. I think this may be device-specific. I've had some reports that OpenSSL libs couldn't be loaded if they were using the same filenames as the BoringSSL libs, and at the time (I don't know if this is still true) BoringSSL did use the original OpenSSL filenames. And I've had some reports of users successfully loading OpenSSL libs even on BoringSSL systems. The OpenSSL filenames are hard-coded in Indy. I would have to add a new API to the IdSSLOpenSSLHeaders unit to allow loading of user-defined filenames.
-
It used to, but Google dropped support for OpenSSL in favor of BoringSSL (their own customized fork of OpenSSL) in Android 6. See this answer on StackOverflow, which I posted about this issue at the time.