Hello All,
I have an off the shelf Windows app that is capable of calling a dll. Actually it calls a C++ wrapper which calls my VB.NET dll ( a VB.NET function ) and all is working fine. The VB.NET dll is designed to open a socket to a server and send messages using System.Net.Sockets. The VB.NET dll also starts a timer to send regular messages to the server in order to keep the socket open and displays a simple UI to handle additional messages that the user might want to send. All this is working fine...but here comes the problem.
When the Windows app wants to send more messages it calls the dll that has previously created the UI and opened the socket that is now sending regular messages. That is to say the socket is already open and being used but I want my Windows app to be able to send additional messages. Long story short, every time the dll is called it wants to start another UI and socket.
I'm stuck with the Windows app and the fact that I have to send messages out through the dll. I also need to keep the socket alive once I open it up by sending regular messages to the server.
What I am wondering is...can I solve this with the current configuration in some way (preferable). Or can I create a separate VB.NET windows application that connects to the server and sends regular messages. Then I would have the messages coming from my off the shelf Windows app call a simplified VB.NET dll that grabs the socket that by VB.NET windows application is using ( if this is possible ) and sends out it's message.
Any help would be greatly appreciated.

Tough one, Share a Socket?
JIM.H.
Thanks for your response.
You are correct. At some point during regular operation the Windows app will call the dll for the first time. The dll opens a socket to a remote machine and sends a single message as well as opening a simple UI to monitor the messages and send additional message manually if need be. Additionally on this first call the dll starts a process of sending regular messages, polling the server as you mentioned. So when first run, the dll has created a "messaging machine" as well as opend a simple UI. Now later on during the day the Windows app is going to call the same dll to try and send more messages out over the already open socket.
The problem is when the dll is called again it has no idea that the socket is already open and that the UI has already been generated. So it will try and do it all again. Is there any way to avoid this Remember this dll has come and gone the first time and left behind this little app. It has no idea it shouldn't do it again.
Is there a way for the the dll, when it is run subsequent the to original run, to detect if there is an open socket and send messages out over it In addition detect if there is already the UI up and running and not create another Oh and I'd also like to have access to the components on the UI so that I can do thinks like change text in RichTextBoxes. I'm having trouble trapping this and I'm wondering if there is a clever way to do this.
The only alternative I can think of is to build a completely seperate app with VB.NET...call it "myApp". I would have this app, with the UI, have the capability of login, open socket, and send regular messages. Then if it is possible I could have the dll that the Windows app calls detect myApp and send messages out over it's socket (if possible) as well as edit it's RichTextBoxes (if possible).
Thanks for any help you can provide.
noggin
Thank you. I think you understand the problem correctly. My apologies if my explanation has been unclear but I think you have it. The dll that the Windows app is calling is the one I have coded...you are correct.< xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
I have a concern but maybe I do just not understand your solution correctly. The send message request is just the Window's app calling my dll ( a VB.NET function ) and passing it a string. Based on the string I know what type of message to send from the dll. Once it's been called and my dll function returns a value, the Windows app has no ability to reference or know about the UI and socket that was opened by the dll. It's just going to run it again when it needs it. Now if what your are saying is I can run the same dll and check to see if there is an existing UI and socket on the system and I can reference and use them...then I say *great*. If I can reference the timer thread then I can just do something simple like stop and restart it while my message is sent out.
If a better solution would be to create a completely separate VB.NET application as the UI and socket with regular messages going out. And I could create a simple dll for the Windows app to call that would reference all the bits of my application, such as the UI the socket and the timer thread for regular messages that would be great. Perhaps this is preferable
Any example code you could provide would be great...thanks for your help!
Grant Holliday
Ok ... there are two simple 'solutions' that spring immediately to mind; the most appropriate depending on how the windows application expects the messaging system to work (ie synchronously or asynchronously). Hopefully one of them, or perhaps a combination will set you off on the right track.
The somewhat rough outline of a synchronous solution may end up looking something like Fig 1.
This example demonstrates the principle of holding a shared reference to an object instance (in this case the socket and the UI form). By shared, I mean one that all instances of MsgPump can access and not one that is encapsulated within the type instance. Whether sharing these variables is necessary, depends on whether the windows application creates a new instance of MsgPump each time it sends or message, or if it creates it just once (the latter situation not requiring the sharing of the variables).
A more preferable solution could be created if the call to SendMsg from the Windows application can be handled asynchronously. You could create a message queue that the SendMsg method simply appends to Private Shared ReadOnly mMQ As New Generic.Queue(Of String) and use the timer's callback to send any messages and update the UI in one go. This would help you to keep the main synchronisation code in one place ... See Fig 2 for a rough guide on how to do this. If you take this approach, be careful and make sure you don't flood the socket.
If any of this needs further clarification, let me know
Richard
FIG 1
Public NotInheritable Class MsgPump
Private Shared ReadOnly mSyncRoot As New Object
Private Shared ReadOnly mTimer As New Threading.Timer(New Threading.TimerCallback(AddressOf MsgPump.TimerCallback)) Private Shared mSocket As Net.Sockets.Socket, mUI As Form Private Delegate Sub SendToUIDelegate(ByVal msg As String)
Public Sub SendMsg(ByVal msg As String) SyncLock MsgPump.mSyncRoot If MsgPump.mSocket Is Nothing Then CreateConnection() If mUI Is Nothing Then CreateUI()MsgPump.Socket.Send( ......... )
MsgPump.SendToUI(msg)
End SyncLock End Sub Private Shared Sub SendToUI(ByVal msg As String) If mUI.InvokeRequired ThenmUI.Invoke(
New SendToUIDelegate(AddressOf MsgPump.SendToUI), msg) Else : mUI.LastMsgTextBox.Text = msg End If End Sub Private Shared Sub TimerCallback(ByVal state As Object) SyncLock MsgPump.mSyncRoot '' Similar to the send message method End SyncLock End SubEnd
ClassFIG 2
Public Sub SendMsg(ByVal msg As String) SyncLock MsgPump.mSyncRoot : MsgPump.mMQ.Enqueue(msg) : End SyncLock End Sub Private Shared Sub TimerCallback(ByVal state As Object) SyncLock MsgPump.mSyncRootIf MsgPump.mSocket Is Nothing Then CreateConnection()
If mUI Is Nothing Then CreateUI() Do Dim msg As String = MsgPump.mMQ.Dequeue If msg Is Nothing Then ReturnMsgPump.mSocket.Send( ...... )
SendToUI(msg)
Loop End SyncLock End SubJim Altrichter
I am working on the understanding that the dll that generates the UI and connects to the server is the one you have coded.
If the 'send message' request always comes in on the same thread, then you can refer to the form by type name as opposed to creating a new instance. This is a VB 'feature', and a simple way to tackle this, though I would personally err away from it.
Is there a reason that the plugin class that the windows application communicates with cannot hold onto a module scope reference of the form/socket. The first time in, the references would be null and you would create the form/socket. Each time after this, you would check for a null reference (Is Nothing) and discover it has already been created. Holding a reference to the form will also allow you to access its members (eg the controls on it).
You would have to be careful when trying to send a message on the socket if you have a background thread/timer handling sending the polling message. This is called multi-threading and means that more than one execution thread (bit of code) could theoretically try to send messages at the same time, possibly causing an exception.
The work around is a simple one. Declare a module scoped object ... Private ReadOnly mSyncRoot As New Object and before you interact with either the form or the socket, add the following line of code SyncLock Me.mSyncRoot (you could of course declare it as a static member if that is a better design).
The only other thing to remember is that you must access the Form members on the same thread that create the form instance. This again is simple by calling mForm.InvokeRequired. If this returns false, you are one the correct thread and can interact with the form normally. If it returns True, you should call your methods using a delegate through the mFrom.Invoke method.
If the above sounds like it might be the solution you are after, I will gladly spend a little time putting together a code example for you if it would help ... let me know.
If the above turns out to have missed the point :), please let me know a bit more detail.
Richard
Tryin2Bgood
Hi
If I have understood this ... you have a windows application that uses your dll as a type of plugin. The plugin sends packets to a remote machine to keep the remote connection alive.
What you now need is the ability to send further messages to the same server that have either been provided by the user (although you already have that working), or the windows application hosting your assembly.
My first question is .. .why are you polling the server to keep the socket alive
HuWu
Why doesn't your UI simply send messages over the existing connection It sounds like that is what you need. Really, the UI should care less about sockets - all it cares is the messages it sends to a server and any messages recieved.
Your DLL should just be a wrapper around the socket functionality: send the DLL a message, the DLL connects as necessary and sends the message. When it recieves a message, it tells the UI it has a message. All of this is consideredthe overall design.
Dick Donny has the right dea considering the practical side of things: the DLL enqueues the UI messages, which are then Dequeued by your socket client thread (although I haven't looked at that code in any detail, it sounds about right - although I'm not sure why an 'invokerequired' is necessary).
Weston Williams
Hi,
Could you create a button which creates a NEW instance of a FORM,
and a NEW instance of a socket in your application via a CLASS
So the new form would use the CLASS having a NEW method in it.
The line of code might be something like.>>
Dim mySocket As New Socket(socketNumber)
If you can have the word "Socket" as a CLASS name that is.
Alternatively can you not use Process.Start
to start a new instance of your application
See.>>
http://msdn2.microsoft.com/en-us/library/0w4h05yb.aspx
If you have more than one browser installed you can have more than one connection to the same server so i guess you can have more than one socket connection to the same server too. :-)
This is all handled by one or more of the Transfer Protocols.
Regards,
S_DS