Baxing 0 Posted March 7, 2022 (edited) Hello, I have tested connecting to Web Socker Server with Component TWSocket on Delphi IntraWeb Application. But an error occurred as attached picture. The command for connecting to Socket server is used within the TIWButton's OnAsyncClick event with the following commands: with sktClient do begin Proto := 'tcp'; Port := 'localhost'; Addr := 'telnet'; LineMode := True; LineEnd := #13#10; Connect; end which this command can be used normally on VCL.. Please guide me for use ICS Sockets components normally on Delphi IntraWeb. Because now I can't connect and send/receive any data if using ICS Sockets components on Delphi IntraWeb application. Thanks Edited March 7, 2022 by Baxing Share this post Link to post
FPiette 383 Posted March 7, 2022 I have zero knowledge about IntraWeb but I call tell you the requirement for ICS : You need a message pump to have the events triggered. If IntraWeb lacks a message pump, you may pump all your ICS stuff within a single thread having his own message pump. Share this post Link to post
Angus Robertson 574 Posted March 7, 2022 Know nothing about IntraWeb, what IP addresses did you configure it to listen on? There are several ICS samples that illustrate simple TCP connect. For simple telnet, you would be better off using TIcsIpStrmLog than TWSocket, much faster and easier to use, see sample OverbyteIcsIpStmLogTst,dpr. Angus Share this post Link to post
Baxing 0 Posted March 7, 2022 I want to send data between multi client and server privately with TCP for some specific work. In the beginning I tested via localhost as the first step. Before putting the server part on the real server and in production I will use SSL as well. I think using TWSocket(TSslWSocket) for Client (on Delphi Intrraweb App.) and TWSocketServer(TSslWSocketServer) for Server (on VCL) is the answer. How to use message pump? Is there a usage example to suggest me? or Using TICsIpStrmLog can do as I want please tell me. I've just used the ICS for the first time and tested it on VCL from the available samples and enough to be quite as I want. But encountered a problem when using it with IntraWeb. Please help guide me again. Share this post Link to post
Angus Robertson 574 Posted March 7, 2022 TICsIpStrmLog can be configured as a server or client, it is a much easier to use version of TWSocket/TWSocketServer, and supports SSL/TLS. The sample application I mentioned can run as both client and server at the same time, sending data to itself. Or you can run two instances on separate PCs sending data to each other. Once connected, there is one event to send a string of data, and another event that receives strings, very simple to use. Unfortunately, the sample looks complicates because it illustrates all the features of the component. Angus Share this post Link to post
Baxing 0 Posted March 7, 2022 I'll try to test it according to your suggestion. and try to send data from server to specified cleint. Share this post Link to post
Baxing 0 Posted March 7, 2022 Now, I using IntraWeb version 15.2.37 on Delphi 10.3.3 (and using ICS Version 8.68) Share this post Link to post
FPiette 383 Posted March 7, 2022 Can you confirm if IntraWeb has a message pump? To check, use Classes.AllocateHWnd to create a hidden window handle and attache a WndProc to it. Then from a button in your user interface, PostMessage a message to that window handle and from the WndProc, check if the message is received. First check in a normal VCL application to be sure you understand how it works. Then check within an IntraWeb application. Share this post Link to post
Baxing 0 Posted March 8, 2022 I can't do it, Please give me a sample code for VCL and I will try it in the IntraWeb app. Share this post Link to post
FPiette 383 Posted March 8, 2022 Here is a sample simple application: Delphi unit : unit WinHandleTestMain; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls; type TForm1 = class(TForm) CreateHWNDButton: TButton; Memo1: TMemo; PostMessageButton: TButton; DestroyHWNDButton: TButton; procedure CreateHWNDButtonClick(Sender: TObject); procedure DestroyHWNDButtonClick(Sender: TObject); procedure PostMessageButtonClick(Sender: TObject); private FWinHandle : HWND; procedure WndProc(var Msg: TMessage); public constructor Create(AOwner : TComponent); override; end; var Form1: TForm1; implementation {$R *.dfm} constructor TForm1.Create(AOwner: TComponent); begin inherited; FWinHandle := INVALID_HANDLE_VALUE; end; procedure TForm1.CreateHWNDButtonClick(Sender: TObject); begin if FWinHandle <> INVALID_HANDLE_VALUE then begin System.Classes.DeallocateHWnd(FWinHandle); FWinHandle := INVALID_HANDLE_VALUE; Memo1.Lines.Add('Window handle destroyed') end; FWinHandle := System.Classes.AllocateHwnd(WndProc); if FWinHandle = INVALID_HANDLE_VALUE then Memo1.Lines.Add('Error creating window handle') else Memo1.Lines.Add(Format('Window handle create %d', [FWinHandle])); end; procedure TForm1.DestroyHWNDButtonClick(Sender: TObject); begin if FWinHandle = INVALID_HANDLE_VALUE then Memo1.Lines.Add('Window handle not created yet') else begin System.Classes.DeallocateHWnd(FWinHandle); FWinHandle := INVALID_HANDLE_VALUE; Memo1.Lines.Add('Window handle destroyed') end; end; procedure TForm1.PostMessageButtonClick(Sender: TObject); begin if FWinHandle = INVALID_HANDLE_VALUE then Memo1.Lines.Add('Window handle not created') else if not PostMessage(FWinHandle, WM_USER, 1234, 5678) then Memo1.Lines.Add('PostMessage failed'); end; procedure TForm1.WndProc(var Msg: TMessage); begin Memo1.Lines.Add(Format('MSG=%d', [Msg.Msg])); end; end. The VCL form: object Form1: TForm1 Left = 0 Top = 0 Caption = 'Form1' ClientHeight = 289 ClientWidth = 382 Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -12 Font.Name = 'Segoe UI' Font.Style = [] PixelsPerInch = 96 TextHeight = 15 object CreateHWNDButton: TButton Left = 40 Top = 32 Width = 98 Height = 25 Caption = 'Create HWND' TabOrder = 0 OnClick = CreateHWNDButtonClick end object Memo1: TMemo Left = 40 Top = 72 Width = 297 Height = 185 Lines.Strings = ( 'Memo1') TabOrder = 1 end object PostMessageButton: TButton Left = 144 Top = 32 Width = 89 Height = 25 Caption = 'PostMessage' TabOrder = 2 OnClick = PostMessageButtonClick end object DestroyHWNDButton: TButton Left = 240 Top = 32 Width = 97 Height = 25 Caption = 'Destroy HWND' TabOrder = 3 OnClick = DestroyHWNDButtonClick end end Share this post Link to post
Chris Rutkowski 1 Posted March 8, 2022 Hi Baxing, Address and port are interchanged: address should be localhost and port should be telnet. 1 Share this post Link to post
FPiette 383 Posted March 9, 2022 As Chris Rutkow said above, you code: with sktClient do begin Proto := 'tcp'; Port := 'localhost'; Addr := 'telnet'; LineMode := True; LineEnd := #13#10; Connect; end Should become: with sktClient do begin Proto := 'tcp'; Port := 'telnet'; Addr := '127.0.0.1'; // Using dotted IP is faster LineMode := True; LineEnd := #13#10; Connect; end; Share this post Link to post
Baxing 0 Posted March 9, 2022 Hello, Chris Rutkow, FPiette I've changed that setting port and addr but still having the same problem. (Invalid argument (#10022 in WSAAsyncSelect) I found that if I put the connection code to event OnFormShow, it will be able to connected the server normally. But can not be used on event AsyncClick of any control, which in use is required on this event. Thanks Share this post Link to post
Baxing 0 Posted March 9, 2022 Hello FPiette, This is result of you sample code on VCL Application when press Create Hwnd and Post Message button and IntraWeb Application when press Create Hwnd and Post Message button Share this post Link to post
FPiette 383 Posted March 9, 2022 (edited) Probably no message pump. Let's add the error number to know more. Replace Memo1.Lines.Add('PostMessage failed'); by Memo1.Lines.Add(Format('PostMessage failed with error %d', [GetLastError])); then try again and tell us the error code PostMessage returns. Edited March 9, 2022 by FPiette Share this post Link to post
Baxing 0 Posted March 9, 2022 1 hour ago, FPiette said: Probably no message pump. Let's add the error number to know more. Replace Memo1.Lines.Add('PostMessage failed'); by Memo1.Lines.Add(Format('PostMessage failed with error %d', [GetLastError])); then try again and tell us the error code PostMessage returns. This Error code : PostMessage failed with error 1400 Share this post Link to post
FPiette 383 Posted March 9, 2022 Windows Error code 1400 is ERROR_INVALID_WINDOW_HANDLE this means PostMessage has not received the handle created. Make sure the is no typo in the code you copied from my example and once more change the line to : Memo1.Lines.Add(Format('PostMessage failed with error %d (HWND=%d)', [GetLastError, FWinHandle])); The handle value should be the same as the one displayed after call to AllocateHWnd. One possible mistake you have done is not passing FWinHandle to PostMessage. Share this post Link to post
Baxing 0 Posted March 9, 2022 I show you for coding from your sample in my IntraWeb application unit Unit1; interface uses Classes, SysUtils, IWAppForm, IWApplication, IWColor, IWTypes, IWCompMemo, Vcl.Controls, IWVCLBaseControl, IWBaseControl, IWBaseHTMLControl, IWControl, IWCompButton, Winapi.Windows, Winapi.Messages; type TIWForm1 = class(TIWAppForm) BTNCreateHwnd: TIWButton; BTNPostMessage: TIWButton; BTNDestroyHwnd: TIWButton; MMO1: TIWMemo; procedure BTNCreateHwndAsyncClick(Sender: TObject; EventParams: TStringList); procedure BTNDestroyHwndAsyncClick(Sender: TObject; EventParams: TStringList); procedure BTNPostMessageAsyncClick(Sender: TObject; EventParams: TStringList); private FWinHandle : HWND; procedure WndProc(var Msg: TMessage); public constructor Create(AOwner : TComponent); override; end; implementation {$R *.dfm} { TIWForm1 } procedure TIWForm1.BTNCreateHwndAsyncClick(Sender: TObject; EventParams: TStringList); begin if FWinHandle <> INVALID_HANDLE_VALUE then begin System.Classes.DeallocateHWnd(FWinHandle); FWinHandle := INVALID_HANDLE_VALUE; mmo1.Lines.Add('Window handle destroyed') end; FWinHandle := System.Classes.AllocateHwnd(WndProc); if FWinHandle = INVALID_HANDLE_VALUE then mmo1.Lines.Add('Error creating window handle') else mmo1.Lines.Add(Format('Window handle create %d', [FWinHandle])); end; procedure TIWForm1.BTNDestroyHwndAsyncClick(Sender: TObject; EventParams: TStringList); begin if FWinHandle = INVALID_HANDLE_VALUE then mmo1.Lines.Add('Window handle not created yet') else begin System.Classes.DeallocateHWnd(FWinHandle); FWinHandle := INVALID_HANDLE_VALUE; mmo1.Lines.Add('Window handle destroyed') end; end; procedure TIWForm1.BTNPostMessageAsyncClick(Sender: TObject; EventParams: TStringList); begin if FWinHandle = INVALID_HANDLE_VALUE then mmo1.Lines.Add('Window handle not created') else if not PostMessage(FWinHandle, WM_USER, 1234, 5678) then // mmo1.Lines.Add('PostMessage failed'); // mmo1.Lines.Add(Format('PostMessage failed with error %d', [GetLastError])); mmo1.Lines.Add(Format('PostMessage failed with error %d (HWND=%d)', [GetLastError, FWinHandle])); end; constructor TIWForm1.Create(AOwner: TComponent); begin inherited; FWinHandle := INVALID_HANDLE_VALUE; end; procedure TIWForm1.WndProc(var Msg: TMessage); begin mmo1.Lines.Add(Format('MSG=%d', [Msg.Msg])); end; initialization TIWForm1.SetAsMainForm; end. And this is result to show GetLastError, FWinHandle (click CreateHwnd and then click PostMessage buttons) Thank you Share this post Link to post
FPiette 383 Posted March 9, 2022 So the handle is correct and yet the error 1400 (Invalid handle) is triggered. Maybe PostMessage is not the one we think it is. Try with a fully qualified name: procedure TForm1.PostMessageButtonClick(Sender: TObject); begin if FWinHandle = INVALID_HANDLE_VALUE then Memo1.Lines.Add('Window handle not created') else if not WinApi.Windows.PostMessage(FWinHandle, WM_USER, 1234, 5678) then Memo1.Lines.Add(Format('PostMessage failed with error %d (HWND=%d)', [GetLastError, FWinHandle])); end; Share this post Link to post
Baxing 0 Posted March 9, 2022 1 hour ago, FPiette said: So the handle is correct and yet the error 1400 (Invalid handle) is triggered. Maybe PostMessage is not the one we think it is. Try with a fully qualified name: procedure TForm1.PostMessageButtonClick(Sender: TObject); begin if FWinHandle = INVALID_HANDLE_VALUE then Memo1.Lines.Add('Window handle not created') else if not WinApi.Windows.PostMessage(FWinHandle, WM_USER, 1234, 5678) then Memo1.Lines.Add(Format('PostMessage failed with error %d (HWND=%d)', [GetLastError, FWinHandle])); end; Hello It give same result Share this post Link to post
FPiette 383 Posted March 10, 2022 Now I'm convinced that this is an issue with IntraWeb. The test program has nothing to do with ICS. It only make use of the same fundamental Windows functions that ICS uses. If the test program doesn't work, then ICS won't work either. I suggest you contact IntraWeb support with the test programs (Both VCL and IntraWeb) so that they can fix their code. Share this post Link to post
Baxing 0 Posted March 10, 2022 Hello FPiette, OK, Thank you very much for the suggestion and good feedback on my problem. Share this post Link to post
FPiette 383 Posted March 10, 2022 You're welcome. Whenever you get the solution, please post it here. Share this post Link to post
Remy Lebeau 1394 Posted March 11, 2022 (edited) 18 hours ago, FPiette said: Now I'm convinced that this is an issue with IntraWeb. 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. Quote The test program has nothing to do with ICS. And the failing code has nothing to do with IntraWeb itself, but rather with the Win32 API directly. Edited March 11, 2022 by Remy Lebeau Share this post Link to post