I created a one way client server communication so that the client can send messages to the server which just receives them. How can I modify the code so that both the server and the client can send and receive messages.
Client Code:
TCPControl.vb
Imports System.Net
Imports System.Net.Sockets
Imports System.IO
Public Class TCPControl
Public Client As TcpClient
Public DataStream As StreamWriter
Public Sub New(Host As String, Port As Integer)
' CLIENT
Client = New TcpClient(Host, Port)
DataStream = New StreamWriter(Client.GetStream)
End Sub
Public Sub Send(Data As String)
DataStream.Write(Data & vbCrLf)
DataStream.Flush()
End Sub
End Class
Form1.vb
Public Class Form1
Private Client As TCPControl
Private Sub cmdSend_Click(sender As System.Object, e As System.EventArgs) Handles cmdSend.Click
SendMessage()
txtMessage.Clear()
txtMessage.Focus()
End Sub
Private Sub cmdConnect_Click(sender As System.Object, e As System.EventArgs) Handles cmdConnect.Click
Client = New TCPControl("10.0.0.253", 64555)
If Client.Client.Connected Then cmdConnect.Text = "Connected"
End Sub
Private Sub Form1_FormClosing(sender As Object, e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
If Client.Client.Connected = True Then
Client.DataStream.Close()
Client.Client.Close()
End If
End Sub
Private Sub txtMessage_KeyDown(sender As Object, e As System.Windows.Forms.KeyEventArgs) Handles txtMessage.KeyDown
If e.KeyCode = Keys.Enter Then SendMessage()
End Sub
Private Sub SendMessage()
If Client.Client.Connected = True Then Client.Send(txtMessage.Text)
End Sub
End Class
Server Code:
TCPControl.vb
Imports System.IO
Imports System.Net
Imports System.Net.Sockets
Imports System.Threading
Public Class TCPControl
Public Event MessageReceived(sender As TCPControl, Data As String)
' SERVER CONFIG
Public ServerIP As IPAddress = IPAddress.Parse("10.0.0.253")
Public ServerPort As Integer = 64555
Public Server As TcpListener
Private CommThread As Thread
Public IsListening As Boolean = True
' CLIENTS
Private Client As TcpClient
Private ClientData As StreamReader
Public Sub New()
Server = New TcpListener(ServerIP, ServerPort)
Server.Start()
CommThread = New Thread(New ThreadStart(AddressOf Listening))
CommThread.Start()
End Sub
Private Sub Listening()
' CREATE LISTENER LOOP
Do Until IsListening = False
' ACCEPT INCOMING CONNECTIONS
If Server.Pending = True Then
Client = Server.AcceptTcpClient
ClientData = New StreamReader(Client.GetStream)
End If
' RAISE EVENT FOR INCOMING MESSAGES
Try
RaiseEvent MessageReceived(Me, ClientData.ReadLine)
Catch ex As Exception
End Try
' REDUCE CPU USAGE
'Thread.Sleep(100)
Loop
End Sub
End Class
Public Class Form1
Private Server As TCPControl
Private Sub Form1_FormClosing(sender As Object, e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
Server.IsListening = False
End Sub
TCPControl.vb
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
Server = New TCPControl
txtChat.Text = ":: SERVER STARTED ::" & vbCrLf
AddHandler Server.MessageReceived, AddressOf OnLineReceived
End Sub
' ALLOW THREAD TO COMMUNICATE WITH FORM CONTROL
Private Delegate Sub UpdateTextDelegate(TB As TextBox, txt As String)
' UPDATE TEXTBOX
Private Sub UpdateText(TB As TextBox, txt As String)
If TB.InvokeRequired Then
TB.Invoke(New UpdateTextDelegate(AddressOf UpdateText), New Object() {TB, txt})
Else
If txt IsNot Nothing Then TB.AppendText(txt & vbCrLf)
End If
End Sub
' UPDATE TEXT WHEN DATA IS RECEIVED
Private Sub OnLineReceived(sender As TCPControl, Data As String)
UpdateText(txtChat, Data)
End Sub
End Class
Related
i want to add a google chrome control to my application because internet explorer control isnt very good.It shows the web pages wrong etc.Some help please
if you want replace internet explorer with chrome in your winforms you must have to include third party tool (library). now a days there many some of that are
1] Selenium
2] CefSharp
3] DotNet Browser
4] OpenWebKitSharp
given list are only some browser . you could also google it out "winform replace webbrowser with chrome".
Thanks
my friend please refere to code given below.
Imports Microsoft.Win32
Imports System
Imports System.Collections
Imports System.ComponentModel
Imports System.Drawing
Imports System.Runtime.CompilerServices
Imports System.Windows.Forms
Imports mshtml
Imports System.Net
Imports System.IO
Imports System.Text
Imports System.Drawing.Imaging
Imports OpenQA.Selenium.Chrome.ChromeDriver
Imports OpenQA.Selenium
Imports OpenQA.Selenium.Interactions
Imports OpenQA.Selenium.Interactions.Actions
Imports OpenQA.Selenium.Support.UI
Imports OpenQA.Selenium.Chrome
Imports OpenQA.Selenium.Support.Events
Imports System.Text.RegularExpressions
Public Class CLOGIN
Public MASTERID As String = ""
Public MASTERPASSWORD As String = ""
Dim webbrowse As New WebBrowser()
Private _DOCUMENTREADY As Integer
Private ERRORSFOUND As Boolean
Private RequestID As String
Private READYSTATE As Boolean
Public mconfig As New MasterConfig()
Public GSTCAPTCHA As New CommonCaptcha()
Private CaptchaCookie = ""
Private WEBSTATEINC As Boolean = True
Public wbr As New Chrome.ChromeDriver(mconfig.MASTERSERVICE, mconfig.MASTEROPTION)
Public WithEvents driver As New EventFiringWebDriver(wbr)
Private Sub CLOGIN_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
AddHandler driver.Navigated, AddressOf OnNavigated
RECALL()
End Sub
Public Function CropImage(ByVal source As Bitmap, ByVal section As Rectangle) As Bitmap
Dim bmp As New Bitmap(section.Width, section.Height)
Dim g As Graphics = Graphics.FromImage(bmp)
g.DrawImage(source, 0, 0, section, GraphicsUnit.Pixel)
Return bmp
End Function
Private Sub WebBrowser1_DocumentCompleted(ByVal sender As System.Object, ByVal e As System.Windows.Forms.WebBrowserDocumentCompletedEventArgs)
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
End Sub
Public Sub RECALL()
INITLABEL:
wbr.Url = "https://example.com/services/do_login"
wbr.Navigate()
System.Threading.Thread.Sleep(2500)
Application.DoEvents()
If Not wbr.Url.Contains("/do_login") Then
GoTo INITLABEL
End If
Dim origialheight = Me.MdiParent.Height
Dim dblheight = origialheight * 0.75
Dim proportedration = origialheight - dblheight
Dim maxwidth = Me.MdiParent.Width
Me.MdiParent.WindowState = FormWindowState.Normal
Me.MdiParent.Location = New Point(0, dblheight + 1)
Me.MdiParent.Size = New Size(maxwidth, proportedration) 'dblheight
wbr.Manage().Window().Size = New System.Drawing.Size(maxwidth, dblheight) 'dblheight
wbr.Manage().Window().Position = New Point(0, 0)
Dim action As New Actions(wbr)
Dim wait As New WebDriverWait(wbr, System.TimeSpan.FromSeconds(5))
wait.Until(ExpectedConditions.ElementExists(By.Id("username")))
wbr.FindElement(By.XPath("//*[#id='username']")).SendKeys(MASTERID) 'txtuserid.Text
wbr.FindElement(By.XPath("//*[#id='user_pass']")).SendKeys(MASTERPASSWORD)
Threading.Thread.Sleep(3000)
Application.DoEvents()
Dim master = ""
wbr.FindElement(By.XPath("//*[#id='captcha']")).SendKeys(OpenQA.Selenium.Keys.Tab)
End Sub
Private Sub btnlogout_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnlogout.Click
End Sub
Private Sub lblshowpass_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lblshowpass.CheckedChanged
If lblshowpass.Checked Then
txtpassword.PasswordChar = ""
Else
txtpassword.PasswordChar = "*"
End If
End Sub
Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click, Button5.Click
wbr.FindElement(By.XPath("//*[#id='captcha']")).SendKeys(TextBox2.Text)
wbr.FindElement(By.XPath("//*[#type='submit']")).Submit()
WaitUntilDocumentIsReady(TimeSpan.FromSeconds(5))
System.Threading.Thread.Sleep(1500)
Application.DoEvents()
If wbr.Url.Contains("/login") Then
Dim wait As New WebDriverWait(wbr, System.TimeSpan.FromSeconds(3)) 'you can play with the time integer to wait for longer than 15 seconds.`
Try
Dim myLink = wbr.FindElementByXPath("//*[#data-ng-if='loginform.captcha.$error.invalid_captcha']")
If Not myLink Is Nothing Then 'wbr.PageSource.Contains("Enter valid Letters shown") Then
MsgBox("Invalid Captcha Code", MsgBoxStyle.Critical, "Application Error")
wbr.FindElement(By.XPath("//*[#id='user_pass']")).SendKeys(txtpassword.Text)
Me.TextBox1.Text = ""
Me.TextBox1.Focus()
End If
Catch ex As Exception
End Try
Try
If wbr.PageSource.Contains("class=""alert alert-danger""") Then
MsgBox("Invalid User ID or Password", MsgBoxStyle.Critical, "Application Error")
wbr.Dispose()
Application.Exit()
End If
Catch ex As Exception
End Try
Else
wbr.Manage().Window().Maximize()
Me.MdiParent.WindowState = FormWindowState.Minimized
End If
End Sub
Public Sub ReCaptcha(ByVal wbr As ChromeDriver)
End Sub
Public Sub OnNavigated(ByVal sender As Object, ByVal e As Support.Events.WebDriverNavigationEventArgs) Handles driver.Navigated
If wbr.Url.Contains("/do_login") Then
Dim wait As New WebDriverWait(wbr, System.TimeSpan.FromSeconds(3))
Try
Dim myLink = wbr.FindElementByXPath("//*[#data-ng-if='loginform.captcha.$error.invalid_captcha']")
If Not myLink Is Nothing Then 'wbr.PageSource.Contains("Enter valid Letters shown") Then
MsgBox("Invalid Captcha Code", MsgBoxStyle.Critical, "Application Error")
wbr.FindElement(By.XPath("//*[#id='user_pass']")).SendKeys(txtpassword.Text)
Me.TextBox1.Text = ""
Me.TextBox1.Focus()
End If
Catch ex As Exception
End Try
Try
If wbr.PageSource.Contains("class=""alert alert-danger""") Then
MsgBox("Invalid User ID or Password", MsgBoxStyle.Critical, "Application Error")
wbr.Dispose()
Application.Exit()
End If
Catch ex As Exception
End Try
Else
End If
End Sub
Public Sub truncateUnfinish(ByVal string1 As String)
If Not IsNumeric(string1) Then
Return
End If
Dim answer = Regex.Replace(string1, "\D", "")
If string1.Length > 6 Then
TextBox2.Text = answer.Substring(0, 6)
End If
End Sub
Function AllCaps(ByVal stringToCheck As String) As Boolean
AllCaps = StrComp(stringToCheck, UCase(stringToCheck), vbBinaryCompare) = 0
End Function
End Class
Thanks.
I'm trying to access to a website variable by it's ID in VB.net. The ID is "value", the data I'm trying to access is the stock price, and the website is linked in the code. I was using the built-in web browser with the next code:
Imports System.Xml
Imports System.Net
Public Class Bolsa
Public Sub New()
InitializeComponent()
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
WebBrowser1.Navigate("https://www.ahorro.com/acnet/fichas/ficha_valor.acnet?isin=ES0113211835&marketCode=09&submarketId=09")
While Not WebBrowser1.ReadyState = WebBrowserReadyState.Complete
Application.DoEvents()
End While
Dim request As String = WebBrowser1.Document.GetElementById("value").InnerText
Dim s As String = request.Replace("<span>", Nothing)
Dim t As String = s.Replace("</span>", Nothing)
TextBox1.Text = t
End Sub
End Class
Now I'm using CefSharp plugin, because I need HTML5 support, but I cannot access the data, and I think the method is correct, I found it in the official site. The actual code:
Imports CefSharp.WinForms
Imports CefSharp
Imports System.Xml
Imports System.Net
Imports System.Treading
Imports System.Treading.Tasks
Public Class Bolsa
Private WithEvents WebClave As ChromiumWebBrowser
Dim cadena
Public Sub New()
InitializeComponent()
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs)
InitializeComponent()
Dim settings As New CefSettings()
CefSharp.Cef.Initialize(settings)
WebClave = New ChromiumWebBrowser("https://www.ahorro.com/acnet/fichas/ficha_valor.acnet?isin=ES0113211835&marketCode=09&submarketId=09")
pANwEB.Controls.Add(WebClave)
End Sub
Private Sub WebClave_IsBrowserInitializedChanged(sender As Object, e As IsBrowserInitializedChangedEventArgs) Handles WebClave.IsBrowserInitializedChanged
If e.IsBrowserInitialized Then
cadena = WebClave.EvaluateScriptAsync("document.getElementById('value').innerHTML")
TextBox1.Text = cadena
End If
End Sub
End Class
Any advice?
Thanks in advance.
[EDIT]: Added full original code
Imports CefSharp
Imports CefSharp.WinForms
Public Class Form1
Public WithEvents browser As ChromiumWebBrowser
Public Sub New()
InitializeComponent()
Dim settings As New CefSettings()
CefSharp.Cef.Initialize(settings)
browser = New ChromiumWebBrowser("https://google.com") With {
.Dock = DockStyle.Fill
}
Panel1.Controls.Add(browser)
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim cvbar = browser.EvaluateScriptAsync("document.getElementById(""lst-ib"").value;")
Dim response = cvbar.Result
If response.Success = True And response.Result <> "" Then
MsgBox(response.Result)
End If
End Sub
End Class
I am trying to create a simple Game which needs a TcpConnection.
So I created a Server class which wraps the TcpListener, same goes with Client and TcpClient. But when I attach my Listener Sub and send Messages it only gets called on the first one:
Server
Imports System.Net.Sockets
Public Class Server
Inherits ConnectionPartner
Private Server As TcpListener
Private Client As TcpClient
Private Stream As NetworkStream
Private Port As Integer
Public Sub Init(ByVal port As Integer)
Server = New TcpListener(port)
End Sub
Public Sub Open()
Server.Start()
Client = Server.AcceptTcpClient()
Stream = Client.GetStream()
End Sub
Public Overrides Sub Write(ByVal Message As String)
Dim Bytes() As Byte = Encoder.GetBytes(Message)
Me.Write(Bytes)
End Sub
Public Overrides Sub Write(ByVal Message() As Byte)
If Stream Is Nothing Then Return
Stream.Write(Message, 0, Message.Length)
End Sub
Public Overrides Sub Listen(ByVal Handler As Action(Of String))
Listen(Sub(ByVal Message() As Byte)
Handler(Encoder.GetString(Message))
End Sub)
End Sub
Public Overrides Sub Listen(ByRef Handler As Action(Of Byte()))
Dim Buffer(Client.ReceiveBufferSize()) As Byte
While (True)
Utils.Log("Listening")
Client.GetStream().Read(Buffer, 0, Buffer.Length)
Handler(Buffer)
End While
End Sub
Public Sub Close()
Try
Client.Close()
Catch ex As Exception
End Try
Try
Server.Stop()
Catch ex As Exception
End Try
End Sub
End Class
Client
Imports System.Net
Imports System.Net.Sockets
Public Class Client
Inherits ConnectionPartner
Private Socket As TcpClient
Private Stream As NetworkStream
Private Port As Integer
Public Sub Init()
Socket = New TcpClient()
End Sub
Public Sub Open(ByVal Ip As IPAddress, ByVal Port As Integer)
Socket.Connect(Ip, Port)
Stream = Socket.GetStream()
End Sub
Public Overrides Sub Write(ByVal Message As String)
Dim Bytes() As Byte = Encoder.GetBytes(Message)
Me.Write(Bytes)
End Sub
Public Overrides Sub Write(ByVal Message() As Byte)
If Stream Is Nothing Then Return
Stream.Write(Message, 0, Message.Length)
End Sub
Public Overrides Sub Listen(ByVal Handler As Action(Of String))
Listen(Sub(ByVal Message() As Byte)
Handler(Encoder.GetString(Message))
End Sub)
End Sub
Public Overrides Sub Listen(ByRef Handler As Action(Of Byte()))
Dim Buffer(Socket.ReceiveBufferSize()) As Byte
While (True)
Utils.Log("Listening")
Stream.Read(Buffer, 0, Buffer.Length)
Handler(Buffer)
End While
End Sub
Public Sub Close()
Try
Socket.Close()
Catch ex As Exception
End Try
End Sub
End Class
My Test Class
Imports System.Net
Imports System.Threading
Class MainWindow
Private Server As Server = New Server()
Private Client As Client = New Client()
Private C As Connection
Private Port As Integer = My.Resources.Port
Private Sub button_client_init_Click(sender As Object, e As RoutedEventArgs) Handles button_client_init.Click
Client.Init()
End Sub
Private Sub button_client_start_Click(sender As Object, e As RoutedEventArgs) Handles button_client_start.Click
Client.Open(Dns.GetHostEntry("localhost").AddressList(1), Port)
End Sub
Private Sub button_client_write_Click(sender As Object, e As RoutedEventArgs) Handles button_client_write.Click
Client.Write("bar")
End Sub
Private Sub button_client_listen_Click(sender As Object, e As RoutedEventArgs) Handles button_client_listen.Click
Dim T As Thread = New Thread(Sub()
Client.Listen(Sub(ByVal M As String)
Log("Client:" & M)
End Sub)
End Sub)
T.Start()
End Sub
Private Sub button_server_init_Click(sender As Object, e As RoutedEventArgs) Handles button_server_init.Click
Server.Init(Port)
End Sub
Private Sub button_server_start_Click(sender As Object, e As RoutedEventArgs) Handles button_server_start.Click
Dim T As Thread = New Thread(Sub()
Server.Open()
End Sub)
T.Start()
End Sub
Private Sub button_server_write_Click(sender As Object, e As RoutedEventArgs) Handles button_server_write.Click
Server.Write("foo")
End Sub
Private Sub button_server_listen_Click(sender As Object, e As RoutedEventArgs) Handles button_server_listen.Click
Dim T As Thread = New Thread(Sub()
Server.Listen(Sub(ByVal M As String)
Log("Server: " & M)
End Sub)
End Sub)
T.Start()
End Sub
End Class
Edit:
I tried to do the whole thing with StreamReader/Writers. Now I am not even getting a síngle Message:
Server
Imports System.IO
Imports System.Net.Sockets
Public Class Server
Inherits ConnectionPartner
Private Server As TcpListener
Private Client As TcpClient
Private Reader As StreamReader
Private Writer As StreamWriter
Private Port As Integer
Public Sub Init(ByVal port As Integer)
Server = New TcpListener(port)
End Sub
Public Sub Open()
Server.Start()
Client = Server.AcceptTcpClient()
Dim Stream As NetworkStream = Client.GetStream()
Reader = New StreamReader(Stream)
Writer = New StreamWriter(Stream)
End Sub
Public Overrides Sub Write(ByVal Message As String)
Writer.WriteLine(Message)
End Sub
Public Overrides Sub Write(ByVal Message() As Byte)
End Sub
Public Overrides Sub Listen(ByVal Handler As Action(Of String))
While True
Dim Message As String = Reader.ReadLine()
Handler(Message)
End While
End Sub
Public Overrides Sub Listen(ByRef Handler As Action(Of Byte()))
End Sub
Public Sub Close()
Try
Client.Close()
Catch ex As Exception
End Try
Try
Server.Stop()
Catch ex As Exception
End Try
End Sub
End Class
Client
Imports System.IO
Imports System.Net
Imports System.Net.Sockets
Public Class Client
Inherits ConnectionPartner
Private Socket As TcpClient
Private Reader As StreamReader
Private Writer As StreamWriter
Private Port As Integer
Public Sub Init()
Socket = New TcpClient()
End Sub
Public Sub Open(ByVal Ip As IPAddress, ByVal Port As Integer)
Socket.Connect(Ip, Port)
Dim Stream As NetworkStream = Socket.GetStream()
Reader = New StreamReader(Stream)
Writer = New StreamWriter(Stream)
End Sub
Public Overrides Sub Write(ByVal Message As String)
Writer.WriteLine(Message)
End Sub
Public Overrides Sub Write(ByVal Message() As Byte)
End Sub
Public Overrides Sub Listen(ByVal Handler As Action(Of String))
While True
Dim Message As String = Reader.ReadLine()
Handler(Message)
End While
End Sub
Public Overrides Sub Listen(ByRef Handler As Action(Of Byte()))
End Sub
Public Sub Close()
Try
Socket.Close()
Catch ex As Exception
End Try
End Sub
End Class
Solution:
Forgot to flush the Messages.
Server
Imports System.IO
Imports System.Net
Imports System.Net.Sockets
Public Class Server
Inherits ConnectionPartner
Private Server As TcpListener
Private Client As TcpClient
Private Reader As StreamReader
Private Writer As StreamWriter
Private Port As Integer
Public Sub Init(ByVal Ip As IPAddress, ByVal Port As Integer)
Server = New TcpListener(Ip, Port)
End Sub
Public Sub Open()
Server.Start()
Client = Server.AcceptTcpClient()
Dim Stream As NetworkStream = Client.GetStream()
Reader = New StreamReader(Stream)
Writer = New StreamWriter(Stream)
Writer.AutoFlush = True
End Sub
Public Overrides Sub Start(ByVal Ip As IPAddress, ByVal Port As Integer)
Me.Init(Ip, Port)
Me.Open()
End Sub
Public Overrides Sub Write(ByVal Message As String)
Writer.WriteLine(Message)
End Sub
Public Overrides Sub Listen(ByVal Handler As Action(Of String))
While True
Dim Message As String = Reader.ReadLine()
Handler(Message)
End While
End Sub
Public Overrides Sub Close()
Try
Client.Close()
Catch ex As Exception
End Try
Try
Server.Stop()
Catch ex As Exception
End Try
End Sub
End Class
Client
Imports System.IO
Imports System.Net
Imports System.Net.Sockets
Public Class Client
Inherits ConnectionPartner
Private Socket As TcpClient
Private Reader As StreamReader
Private Writer As StreamWriter
Private Port As Integer
Public Sub Init()
Socket = New TcpClient()
End Sub
Public Sub Open(ByVal Ip As IPAddress, ByVal Port As Integer)
Socket.Connect(Ip, Port)
Dim Stream As NetworkStream = Socket.GetStream()
Reader = New StreamReader(Stream)
Writer = New StreamWriter(Stream)
Writer.AutoFlush = True
End Sub
Public Overrides Sub Start(ByVal Ip As IPAddress, ByVal Port As Integer)
Me.Init()
Me.Open(Ip, Port)
End Sub
Public Overrides Sub Write(ByVal Message As String)
Writer.WriteLine(Message)
End Sub
Public Overrides Sub Listen(ByVal Handler As Action(Of String))
While True
Dim Message As String = Reader.ReadLine()
Handler(Message)
End While
End Sub
Public Overrides Sub Close()
Try
Socket.Close()
Catch ex As Exception
End Try
End Sub
End Class
TCP does not provide messages at all. It provides a boundaryless stream of bytes. When you Read you can get back any number of bytes as low as one. You code needs to assume arbitrary chunking. Here, you are assuming that you get a full buffer each time.
You can use BinaryReader.ReadBytes to read an exact number of bytes. StreamReader/Writer makes text-based protocols much easier.
ReceiveBufferSize is not the number of bytes incoming. It's value is meaningless, don't look at it.
I have 2 main classes. The first launches the second which implements a FIX dll. I would like to be able to set variables/textbox.text in the first from the second. I am able to do so from te OnCreate method in the second, but for some reason cannot from the OnLogon method. Any ideas ?
Thanks
Imports QuickFix
Public Class GlobalVariable
Inherits MainFIXClass
Public Shared instance As MainFIXClass
End Class
Public Class MainFIXClass
Private Sub CurrencyArb_Load(sender As Object, e As EventArgs) Handles MyBase.Load
GlobalVariable.instance = Me
Connect({"D:\\Config.txt"})
End Sub
Private Sub Connect(args As String())
Dim settings As New QuickFix.SessionSettings(args(0))
Dim myApp As IApplication = New MyQuickFixApp()
Dim storeFactory As QuickFix.IMessageStoreFactory = New FileStoreFactory(settings)
Dim logFactory As QuickFix.ILogFactory = New FileLogFactory(settings)
Dim initiator As New QuickFix.Transport.SocketInitiator(myApp, storeFactory, settings, logFactory)
Try
initiator.Start()
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
End Class
Public Class MyQuickFixApp
Inherits MainFIXClass
Implements IApplication
Private _session As Session = Nothing
Private _settings As QuickFix.Session = Nothing
Private _Store As QuickFix.IMessageStore = Nothing
Private _instance As MainFIXClass
Public Sub OnCreate(sessionID As SessionID) Implements IApplication.OnCreate
_instance = GlobalVariable.instance
_session = Session.LookupSession(sessionID)
_instance.OutputTB.Text = "On Create - " & sessionID.ToString & " " & _session.ToString ' **************************** this line works
End Sub
Public Sub OnLogon(sessionID As SessionID) Implements IApplication.OnLogon
_instance.OutputTB.Text = "Logged On" ' **************************** this line does not work ?????
MsgBox("Logged On")
End Sub
End Class
Imports System.ComponentModel
Imports System.Threading
Imports QuickFix
Imports QuickFix.Fields
Imports QuickFix.MessageCracker
Public Class MainFIXClass
Private WithEvents bw As BackgroundWorker
Delegate Sub ShowOutputDelegate(value As String)
Private Sub CurrencyArb_Load(sender As Object, e As EventArgs) Handles MyBase.Load
GlobalVariable.instance = Me
bw = New BackgroundWorker
bw.RunWorkerAsync()
End Sub
Private Sub bw_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs) Handles bw.DoWork
Dim settings As New QuickFix.SessionSettings("D:\\CurrencyArb.txt")
Dim myApp As IApplication = New MyQuickFixApp()
Dim storeFactory As QuickFix.IMessageStoreFactory = New FileStoreFactory(settings)
Dim logFactory As QuickFix.ILogFactory = New FileLogFactory(settings)
Dim initiator As New QuickFix.Transport.SocketInitiator(myApp, storeFactory, settings, logFactory)
Try
'If Not TypeOf e.Argument Is String() Then 'only take valid input
' Throw New ArgumentException("Invalid argument")
'End If
'Dim args As String() = DirectCast(e.Argument, String()) 'you can pass your arguments here
initiator.Start()
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
Private Sub bw_WorkCompleted(source As Object, e As RunWorkerCompletedEventArgs) Handles bw.RunWorkerCompleted
If e.Error IsNot Nothing Then
'and exception occured
Else
'everything was fine, you can use the result
Dim result As Object = e.Result
End If
End Sub
Public Sub ShowOutput(msg As String)
If InvokeRequired Then
Invoke(New ShowOutputDelegate(AddressOf ShowOutput), msg)
Else
Me.OutputTB.Text = msg
End If
Me.OutputTB.Text = msg
End Sub
End Class
Public Class MyQuickFixApp
Implements IApplication
Private _session As Session = Nothing
Private _settings As QuickFix.Session = Nothing
Private _Store As QuickFix.IMessageStore = Nothing
Private _instance As MainFIXClass
Public Sub OnCreate(sessionID As SessionID) Implements IApplication.OnCreate
_instance = GlobalVariable.instance
_session = Session.LookupSession(sessionID)
_instance.ShowOutput("On Create - " & sessionID.ToString & " " & _session.ToString)
End Sub
Public Sub OnLogon(sessionID As SessionID) Implements IApplication.OnLogon
_instance.ShowOutput("Logged On")
End Sub
End Class
Public Class GlobalVariable
Public Shared instance As MainFIXClass
End Class
To prevent the Window from blocking, you can use Threads or a BackgroundWorker. I prepared a small code snippet that demonstrates how you can use the BackgroundWorker. Please note how the DoWork and WorkCompleted methods are wired to the worker instance by using Handles.
Imports System.ComponentModel
Imports System.Threading
Imports QuickFix
Imports QuickFix.Fields
Imports QuickFix.MessageCracker
Public Class MainFIXClass
Implements IApplication
Private WithEvents bw As BackgroundWorker
Private _session As Session = Nothing
Private _settings As QuickFix.Session = Nothing
Private _Store As QuickFix.IMessageStore = Nothing
#Region "IApplication Methods"
Public Sub OnCreate(sessionID As SessionID) Implements IApplication.OnCreate
_session = Session.LookupSession(sessionID)
Me.ShowOutput("On Create - " & sessionID.ToString & " " & _session.ToString)
End Sub
Public Sub OnLogon(sessionID As SessionID) Implements IApplication.OnLogon
Me.ShowOutput("Logged On")
End Sub
#End Region
Private Sub CurrencyArb_Load(sender As Object, e As EventArgs) Handles MyBase.Load
bw = New BackgroundWorker
bw.WorkerReportsProgress = True
bw.RunWorkerAsync()
End Sub
Private Sub bw_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs) Handles bw.DoWork
Dim settings As New QuickFix.SessionSettings("D:\\CurrencyArb.txt")
Dim myApp As IApplication = New MyQuickFixApp()
Dim storeFactory As QuickFix.IMessageStoreFactory = New FileStoreFactory(settings)
Dim logFactory As QuickFix.ILogFactory = New FileLogFactory(settings)
Dim initiator As New QuickFix.Transport.SocketInitiator(myApp, storeFactory, settings, logFactory)
bw.ReportProgress(0, "Starting initiator")
initiator.Start()
bw.ReportProgress(0, "Initiator started successfully")
End Sub
Private Sub bw_ReportProgress(source As Object, e As ProgressChangedEventArgs) Handles bw.ProgressChanged
Me.ShowOutput(e.UserState.ToString())
End Sub
Private Sub bw_WorkCompleted(source As Object, e As RunWorkerCompletedEventArgs) Handles bw.RunWorkerCompleted
If e.Error IsNot Nothing Then
'and exception occured
MsgBox(e.Error.Message)
Else
'everything was fine, you can use the result
Dim result As Object = e.Result
End If
Me.ShowOutput("Worker finished")
End Sub
Public Sub ShowOutput(msg As String)
Me.OutputTB.Text = msg
End Sub
End Class
Here is a snippet when merging both classes
Imports System.ComponentModel
Imports System.Threading
Imports QuickFix
Imports QuickFix.Fields
Imports QuickFix.MessageCracker
Public Class MainFIXClass
Implements IApplication
Private WithEvents bw As BackgroundWorker
Private _session As Session = Nothing
Private _settings As QuickFix.Session = Nothing
Private _Store As QuickFix.IMessageStore = Nothing
#Region "IApplication Methods"
Public Sub OnCreate(sessionID As SessionID) Implements IApplication.OnCreate
_session = Session.LookupSession(sessionID)
Me.ShowOutput("On Create - " & sessionID.ToString & " " & _session.ToString)
End Sub
Public Sub OnLogon(sessionID As SessionID) Implements IApplication.OnLogon
Me.ShowOutput("Logged On")
End Sub
#End Region
Private Sub CurrencyArb_Load(sender As Object, e As EventArgs) Handles MyBase.Load
bw = New BackgroundWorker
bw.WorkerReportsProgress = True
bw.RunWorkerAsync()
End Sub
Private Sub bw_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs) Handles bw.DoWork
Dim settings As New QuickFix.SessionSettings("D:\\CurrencyArb.txt")
Dim myApp As IApplication = New MyQuickFixApp()
Dim storeFactory As QuickFix.IMessageStoreFactory = New FileStoreFactory(settings)
Dim logFactory As QuickFix.ILogFactory = New FileLogFactory(settings)
Dim initiator As New QuickFix.Transport.SocketInitiator(myApp, storeFactory, settings, logFactory)
bw.ReportProgress(0, "Starting initiator")
initiator.Start()
bw.ReportProgress(0, "Initiator started successfully")
End Sub
Private Sub bw_ReportProgress(source As Object, e As ProgressChangedEventArgs) Handles bw.ProgressChanged
Me.ShowOutput(e.UserState.ToString())
End Sub
Private Sub bw_WorkCompleted(source As Object, e As RunWorkerCompletedEventArgs) Handles bw.RunWorkerCompleted
If e.Error IsNot Nothing Then
'and exception occured
MsgBox(e.Error.Message)
Else
'everything was fine, you can use the result
Dim result As Object = e.Result
End If
Me.ShowOutput("Worker finished")
End Sub
Public Sub ShowOutput(msg As String)
Me.OutputTB.Text = msg
End Sub
End Class
I am having a little trouble understanding how I should be utilizing the Dispatcher to help me solve my problem of accessing a text box from a different thread. What I am trying to achieve is getting the thread to append to a chat box once it receives data form the server.
Public Class ChatScreen
Public client As Client
Private Sub Window_Loaded(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded
client = Application.Current.Properties("Client")
Me.Title = "ChitChat - " & client.Name
txtMessage.Focus()
Dim serverHandler As New ServerHandler(client.clientSocket, client.networkStream, txtChat)
End Sub
Private Sub btnSend_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles btnSend.Click
client.SendMessage(txtMessage.Text)
End Sub
Private Sub Window_KeyDown(ByVal sender As System.Object, ByVal e As System.Windows.Input.KeyEventArgs) Handles MyBase.KeyDown
If e.Key = Key.Enter Then
client.SendMessage(txtMessage.Text)
End If
End Sub
Public Sub AppendToChat(ByVal message As String)
txtChat.AppendText(">> " & message)
End Sub
Public Class ServerHandler
Dim clientSocket As TcpClient
Public networkStream As NetworkStream
Dim thread As Thread
Public Sub New(ByVal clientSocket As TcpClient, ByVal networkStream As NetworkStream)
Me.clientSocket = clientSocket
Me.networkStream = networkStream
thread = New Thread(AddressOf ListenForServer)
thread.Start()
End Sub
Public Sub ListenForServer()
Dim bytesFrom(10024) As Byte
Dim message As String
While True
networkStream.Read(bytesFrom, 0, CInt(clientSocket.ReceiveBufferSize))
message = System.Text.Encoding.ASCII.GetString(bytesFrom)
message = message.Substring(0, message.IndexOf("$"))
'AppendToChat <--- This is where I would like to append the message to the text box
End While
End Sub
End Class
End Class
You can use SynchronizationContext to do this,
Store UI tread context in a variable like this
Private syncContext As SynchronizationContext
Private Sub frmClient_Shown(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Shown
syncContext = AsyncOperationManager.SynchronizationContext
End Sub
Now create a procedure to execute on main UI thread like this
Private Sub AddTextBox()
‘Do whatever you want you are in UI thread here
End Sub
From you background thread post request on UI thread like this
syncContext.Post(New SendOrPostCallback(AddressOf AddTextBox), Nothing)
you can even pass arguments also
Private Sub AddTextBox(ByVal argument As Object)
‘Do whatever you want you are in UI thread here
End Sub
.....
syncContext.Post(New SendOrPostCallback(AddressOf AddTextBox), objToPass)