# VBForums CodeBank > CodeBank - Visual Basic 6 and earlier >  New code for simulating multithreading in VB6...

## Wokawidget

OK, after about 8 months, I have finally got round to finishing off the 2nd revision to my multithreading code I posted here.

This code is more compact, easier to use and has more functionality than that of the previous code, which was to be fair, a little bit of a nightmare to use unless you were quite compitent at VB.

Attached to this post is a ZIP file, which contains the multithreading code itself and 2 demo projects on how to use it.

Some main features of the code:
Ability to send data synchronously and asynchronouslySend data in any format etc long, string, byte array.When sending data synchronously you can return data for the return value of the send function. Just like a normal function in VB, but across threads.Ability to handle and display errors in the thread or pass them back to the calling app.

OK, lets get into the code.

Download the zip file and open it.
Open the vbGateway2 project and compile to your PC.
This is the multithreading "engine" and ALL multithreading code is contained in this project. Just 1 DLL...yup that's right  :Smilie: 

OK, now go into the Demo folder and open project1 project. Compile this to an EXE. This is a small demo and shows you each function that can be accomplished with this code.

Once compiled open 2 instances of the EXE.
Highlight and copy, one of the hWnds in the text box into the other windows child hwnd text box. Notice as soon as you do this both windows captions change to "Connected". The link is made. They can now communicate with each other.

Now click Send Data. this sends the data in the Send Data textbox to the other thread. Notice how it appears in the listbox. The other thread will wait for 1/2 a second before it responds. This pause is ONLY there to demonstrate that it's been sent synchronously, you can remove this pause and then the thread will reply instantly.

The post data method is the same, apart from no reponse is required from the thread and so execution resumes in the calling thread. Does that make sense?

Errors...Right, this is what I have been working on, and it's made life easier in the thread. If an error is raise during a synchronous operation then the error is sent back to the calling thread and a normal error is raised, just like you'd expect if you called a normal function in VB.
There is also asynchronous error handling provided. Obviously sometimes you may not want your threads to Msgbox errors, espescially if they're hidden and running in the back ground. If a thread is set to handle it's own errors then an event is raised and the error can be displayed, otehrwsie the error is posted back to the calling thread, where it's displayed.

The project1 demo shows this by either clicking the create error button. Try this and then toggle the check box and try it again. Notice what thread the error is handled in.

If you try in "ERROR" into the send data text box and click send data then once the data is received in the other thread an error is raised back to the calling thread. This simulates a normal application as if you were calling a normal function in a DLL. very useful.

This demo shows the basics of the multithreading code.
Now for a real world example, the same as last time, a file searching demo.

Open the multithreading folder, and then open the ThreadUI folder. Open the SearchThread project and compile it. This is used for searching files. Many of these threads can be created and multiple searches can take place at the same time. Obviously the more search you have running at the same time the slower your PC will become. This is not the multithreadings codes fault  :Smilie: 

Now open the DemoUI folder and open and compile the demoUI project. This is the main UI calling thread and is used to "spawn" many search threads. Once compiled run the EXE. Click Search and a new thread will spawn. While searching the details of found files are displayed in the thread itself and the current file is posted back to the calling thread, the demoUI exe. Lanuch many searches at the same time, this is where you see the full power of multithreading.

The search code and the demo projects are rough code, obviously all my time and effort has gone into the vbGateway2.dll, which is the backbone of this code.

Any comments will be much appreciated.

Hope this code will help you if your app design.

Wokawidget

PS *I newer release, which is easier to use and has more functionality, is attached to my next post. I left this here for historical reasons.*

----------


## Wokawidget

OK...after a few days of getting annoyed at having to encode and decode the data I sent using the vbGateway2.dll, in my case I used property bags, I decided to write soem code that did this for you.
I have added 3 classes to the vbGateway2.dll project. this are:
CommandParameterParameters
These are used to create a command (function) and it's params.
Say you referenced a DLL in your project and this DLL had the following function in a class called clsUsers:

VB Code:
Public Function FetchUsers(ByVal TaskCount As Long, ByVal Admin As Boolean) As String 'XML return
Then in your UI you would do:

VB Code:
Dim strXML As String
Dim objUsers As clsUsers
   Set objUsers = New clsUsers
   strXML = objUsers.FetchUsers(10, False)
   Set objUsers = Nothing
This is straight forward, although using the vbGateway2.dll meant you had to somehow convert this into a single bit of data and do:

VB Code:
Dim strXML As String
Dim varData As Variant
   'create data that the thread can decode and understand
   strXML = mobjGateway.SendData(varData)
Then is te DataArrived event in the thread you had to decode the data, which can be hard if you are passing lots of encoded parameters.
This annoyed me, and I'm sure it did some of you  :Frown: 
The new command object deals with this for you.
So for the FetchUsers example I used above you would now do:

VB Code:
Private Sub FetchUsers(ByVal plngTaskCount As Long, ByVal plngAdmin As Boolean)
Dim objCommand   As Command
   Set objCommand = New Command
   With objCommand
      .Key = "FetchUsers"
      .Parameters.Add "TaskCount", plngTaskCount
      .Parameters.Add "Admin", pblnAdmin
   End With
   mobjGateway.PostCommand objCommand
   Set objCommand = Nothing
End Sub
Now this is received by the gateway object in the thread and a new event is raised.

VB Code:
Private Sub mobjGateway_CommandArrived(Command As vbGateway2.Command, ByVal Synchronous As Boolean)
What you do now is:

VB Code:
Private Sub mobjGateway_CommandArrived(Command As vbGateway2.Command, ByVal Synchronous As Boolean)
Dim strXML As String
Dim objRet  As Command
   With Command
      Select Case .Key
         Case "FetchUsers"
            strXML = FetchUsers(.Parameters.Item("TaskCount").Value, .Parameters.Item("Admin").Value
            Set objRet = New Command
            objRet.Key = "UsersFetched"
            objRet.Parameters.Add "XML", strXML
            mobjGateway.PostCommand objRet
            Set objRet = Nothing
      End Select
   End With
End Sub
 Private Function FetchUsers(ByVal plngTaskCount As Long, ByVal plngAdmin As Boolean) As String
   'code to laod users from DB
End Function
Then you do pretty much the same thing in the calling thread to handle the return value:

VB Code:
Private Sub mobjGateway_CommandArrived(Command As vbGateway2.Command, ByVal Synchronous As Boolean)
Dim strXML As String
   With Command
      Select Case .Key
         Case "UsersFetched"
            strXML = .Parameters.Item("XML").Value
           'code to deal with users in XML
      End Select
   End With
End Sub
Does this make sense.
I have updated the file searching demo so that it uses this new code. Makes things MUCH MCUH easier  :Smilie:  There is also a new button on the Main UI screen called Cancel ALL searches. This sends a cancel command to ALL threads and terminates their search. This shows how simple it is to send and handle many different command, with or without parameters.

The above exmaple was how to load users Asynchronously...to do it synchronously you would do the following in the UI:

VB Code:
Private Sub FetchUsers(ByVal plngTaskCount As Long, ByVal plngAdmin As Boolean)
Dim strXML As String
Dim objCommand   As Command
   Set objCommand = New Command
   With objCommand
      .Key = "FetchUsers"
      .Parameters.Add "TaskCount", plngTaskCount
      .Parameters.Add "Admin", pblnAdmin
   End With
   strXML = mobjGateway.SendCommand(objCommand)
   Set objCommand = Nothing
End Sub
Then in the thread you would have:

VB Code:
Private Sub mobjGateway_CommandArrived(Command As vbGateway2.Command, ByVal Synchronous As Boolean)
Dim strXML As String
Dim objRet  As Command
   With Command
      Select Case .Key
         Case "FetchUsers"
            strXML = FetchUsers(.Parameters.Item("TaskCount").Value, .Parameters.Item("Admin").Value
            mobjGateway.Reply = strXML
      End Select
   End With
End Sub
Even easier  :Smilie: 

There is also a VERY simple demo of this in the root folder of the vbGateway2 project.
Just load Test.vpg group project and run it.
This simply has 2 buttons, send synchronously and send Asynchronously. This shows you a very simple example.

Just follow the same steps as in the 1st post.

Download the zip file and open it.
Open the vbGateway2 project and compile to your PC

Open the multithreading folder, and then open the ThreadUI folder. Open the SearchThread project and compile it. This is used for searching files. Many of these threads can be created and multiple searches can take place at the same time. Obviously the more search you have running at the same time the slower your PC will become. This is not the multithreadings codes fault  :Smilie: 

If you DO NOT enter a file extension and you have many search threads open then your UI will become unresponsive. this is expected, since the amount of files, and their details, that are being sent to the client is bloody LOADS! and ANY app will become unresponse when dealing with this much data...again, this is not the codes fault.

I hope this helps.

Woof

----------


## jhermiz

Are you ever going to put a seal on this damn project ?

This code sucks badger :Big Grin:   :Big Grin:  

Only cause I can only understand 1/3 of it 
hahahahahah :Alien Frog:

----------


## Edneeis

Sorry it took me so long - I had to install VB6.

Pretty damn good!  I tried the searching example, the Project1 child hWnd example, and the just generally checked out the gateway code.  It likes like the searcher objects are trying to simulate inheritance of the Gateway object.  Pretty clever stuff with handling creating a window and managing its messages.

I hardly do any VB6 work anymore but I tip my hat to ya.

----------


## lozware

Again, I apologize for bringing up an old thread, but I was wondering...

Can you have more than 2 applications that work in a multi-threaded state?

I am planning on having 1 main ActiveX application that has a single class (set to 'multi-use') and multiple instances of another smaller activeX application.

I want the multiple instances of the smaller activeX EXEs to communicate with the main application. From your demo it only looks like you can have 2 applications connected together.

(p.s. I havent had time to look at it in full, so correct me if Im wrong! It looks very good).

----------


## Wokawidget

Old threads are here to be brough up  :Stick Out Tongue: 

Only 2? Where did you gte the value of 2 from?
The demo in the zip is for searching for files...you can start many searches at the same time can you not, and not just 2...???

Woka

----------


## lozware

In the demo that I am using there are only two applications, and they alk to each other. One says Sausages, and the other says Growl. Dont worry about that though, I've worked it out now (I've just taken I more in-depth look at it).

EDIT:
Oh yeah, Im trying to impiment Winsockets into this code (for testing purpoises). Basically I am just using the Demo Application (The Sausage/Growl one) and I have put a Winsock on the form.

When you click a button on one, the winsock starts to listen on port 100. Then, when it retreives a connection request, it ofrwards the RequestID to the other thread...



```
Private Sub Winsock1_ConnectionRequest(ByVal requestID As Long)
mobjGateway.SendData (requestID)
End Sub
```

Then, the other thread attempts to accept the connection request...



```
Private Sub mobjGateway_DataArrived(Data As Variant, ByVal Synchronous As Boolean)
Dim bytReturn()     As Byte
On Error GoTo ErrHandler

    Winsock1.Close
    Winsock1.Accept CLng(Data)

    Exit Sub
ErrHandler:
    mobjGateway.RaiseError Err.Number, Err.Source, Err.Description
End Sub
```

BUT when I try to connect to the application via telnet, the code gets to 'Winsock1.Accept CLng(Data)', and crashes. No runtime errors or anything, it jsut crashes and leaves the Windows XP 'Report Error' dialoge box.

Any idea why its doing this? MSDN says that you can use winsock accross seperate threads, so it should work (however, it doesnt say anything about doing it accross seperate processes).

----------


## Wokawidget

Hahaha, yea, the sausage and growl example  :Big Grin: 

But there should be another demo in that zip. One for searching for files on your PC...?

Woka

----------


## lozware

haha, ok.

But did you take a chance to look at my other problem - its in my last post (I editted it in, its to do with using Winsock).

----------


## Wokawidget

This cannot be done due to it being in a different thread. This was explained in CVMichaels winsock thread.
To pass the requestID to another winsock control they must be running in the same process, in this case, they are not, and thus it will not work. U have to start a new thread to listen for connections.

Woka

----------


## lozware

*AAAAAAAAARRGGGGGGGGGHHHHH!!!!!!!!*

Thanks anyway, nice code.

(p.s. Why did you suggest using this code if you knew that it wouldnt work?!?!)

----------


## Wokawidget

Beacuse...if you read the other thread I explain  :Big Grin: 
U create a NEW thread that listens for incoming connections, and the one that took the RequestID, connects to that request.

Woka

----------


## lozware

But how is that different from what I am doing at the moment? At the mo I have an ActiveX EXE that listens for connection,s nd accepts them. Then, when it does accept a new connection, it loads another instance of itself.

----------


## Wokawidget

well that will work then  :Stick Out Tongue: 
What u cannot do is PASS the requestID to ANOTHER process. This will not work.

Woka

----------


## lozware

It does work, but not very well... this is why I seeked guidance in the first place.

There is a delay between the time that the new connection is accepted, and the time it takes for the new process to start listening. This means that under intense traffic, a lot of connections are not accepted.

Ah well, I will just keep on working on alternative approaches   :Thumb:

----------


## lozware

Whooooo! I just learned how to multithread properly (i.e. Multiple threads under just 1 process). Its absolutely amazing, but Im still having a bit of grief with the ol' Winsock... Im getting pretty damn close though!

----------


## Wokawidget

What code did u use for multithreading?

Woka

----------


## lozware

Ok, here we go...

1) Create a New ActiveX EXE project.

2) Go into Properties, and select 'Thread per Object' (under the General tab), and set the Start-up object to 'Sub Main'.

3) Then click on the Component tab, and set the Start Mode to 'Standalone'.

4) Make 2 forms - one is your main form, and the other will be your thread (the one that you want to create multiple instances of). We will call the main form frmMain, and the thread form frmThread.

5) Make a new module, and put the following code into it...

VB Code:
'Module1 Code----
Public Declare Function GetParent Lib "user32" (ByVal hwnd As Long) As Long
Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Public Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Public Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hwnd As Long, lpdwProcessId As Long) As Long
Public Declare Function GetCurrentProcessId Lib "kernel32" () As Long
Public Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hwnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
Public Declare Function GetNextWindow Lib "user32" Alias "GetWindow" (ByVal hwnd As Long, ByVal wFlag As Long) As Long
Public Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" (ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile As String, ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long
Public Declare Function FindExecutable Lib "shell32.dll" Alias "FindExecutableA" (ByVal lpFile As String, ByVal lpDirectory As String, ByVal lpResult As String) As Long
 Sub Main()
     Dim ProcessID As Long, curProcessID As Long
    hwnd = FindWindow(vbNullString, "Put the Main Form's Caption Here!")
    
    If hwnd <> 0 Then
        GetWindowThreadProcessId hwnd, ProcessID
        curProcessID = GetCurrentProcessId
        
        If curProcessID <> ProcessID Then
            Dim Frm As New frmMain
                Frm.Show
            Set Frm = Nothing
         End If
    End If
      
             
   If hwnd = 0 Then
            Dim Frm2 As New frmMain
                Frm2.Show
            Set Frm2 = Nothing
    End If
End Sub

6) Make a new Class Module, call it Thread, and put the following code into it...

VB Code:
'Project1.Thread Code----
Sub NewFormThread(OwnerObject as Object, MirrorObject as object)
    
    Dim Frm As New frmThread
    
    Frm.Show
    Set MirrorObject = Frm
    Set Frm.OwnerObject = OwnerObject
    Set Frm = Nothing
 End Sub

7) (we're getting there!) In frmThread, create a Public Object variable (notice how the above function requires the form to have one)...

VB Code:
'frmThread Code----
Public OwnerObject as object
This object is going to be how the thread communicates with the main form (frmMain).

8) You're all set to go! When you start the project, the main form will load (provided you made the correct changes to the Sub Main). Then, whenever you want to load a new thread, put this in your code:

VB Code:
'frmMain Code----
Dim Thready As Object
Dim F As Form, tF As Form
Dim Obj As Project1.Thread
 Set Obj = CreateObject("Project1.Thread")
Call Obj.NewFormThread(Me, Thready)
Set Obj = Nothing
 Thready.Winsock.Close               ' Just an example of how to use the 
Thready.Winsock.LocalPort = 23      ' "MirrorObject" to communicate with the 
Thready.Winsock.Listen              ' thread after it has been created.

There you go ladies and gentleman, that is TRUE multithreading! If you want, here is sometihng cool that you can do on the frmThread form so that you know that it is working properly...

VB Code:
'FrmThread Code----
Private Sub Form_Load()
 me.Caption = App.ThreadID
 End Sub


(NOTE: The above code was originally written by Srideep Prasad, all I did was edit it to suit what I needed, and comment on it (duh!))

(NOTE #2: You must run this as a compiled .EXE - the multithreading wont work in the VB IDE environment)

----------


## Wokawidget

No it's not  :Big Grin: 

U honestly think I went to all that trouble to write multithreading code if it were that simple  :Big Grin: 

There is one HUGE flaw with your code.

Say you want to call a function in your activeX control:

VB Code:
Public Sub DoSomething()
Dim lngIndex As Long
   For lngIndex = 0 To 10000
      'code here
   Loop
End SUb
Then when you call this from your UI, the code execution of the UI will stop UNTIL that function has finished. This is bad as it locks the UI and the other threads can therefore no longer raise events to it.
Ok, so it is possible to get around this by using a timer:

VB Code:
Public Sub DoSomething()
   tmrEvent.Enabled = True
End Sub
 Private Sub tmrEvent_Timer()
Dim lngIndex As Long   
    tmrEvent.Enabled = True
    For lngIndex = 0 To 10000
      'code here
   Loop
End Sub
Ok, so this is good. Or soooooo you think.

Lets take the following. 
Your ActiveX control is doing something, lets say it's processing some data from winsock.

VB Code:
Private Sub ProcessData(ByVal pstrData As String)
    'code to do something complicated with data
End Sub
This issue arrives here when the UI tries to communicate with the ActiveX EXE is anyway! Lets say you have a timer on your form that updates the status of the winsock connections in a grid:

VB Code:
Private Sub tmrStatus_Timer()
Dim obj As Thread
    'code to get one ActiveX EXE
   
   lblStatus.Caption = obj.BytesProcessed & " bytes"
End Sub
Now, whe the UI tries to get BytesProcessed you get a lovely "Switch To, Retry" error. Very annoying, very irritating, and it's simpley not good in your app.

This is where my code comes in  :Smilie:  I can communicate with the ActiveX EXE's regardless if they are busy or not, and vis versa. Using your method you cannot.

Almost multithreading, but your code falls at the last hurdle. Trust me on this one.

Woka

----------


## lozware

Where abouts are you saying it would freeze up? If I were to put that loop in one of the threads it would not freeze up - I can give you a working example if you want.

----------


## Wokawidget

If your thread is "doing something" and u tried to access a property of that thread, or try to call a method from that thread. Try it.

On a form in your thread add a button and the do:


VB Code:
Private Sub Command1_Click()
Dim lngIndex As Long
    For lngIndex = 1 To 100000
        Command1.Caption = CStr(lngIndex)
    Next lngIndex
End Sub
Also, to your thread class add the following:

VB Code:
Public Property Get SomeText() As String
   SomeText = "Woof"
End Property
Run your code.
Make the thread do something by clicking the button.
Now, your UI is still active and will not hang. This is good.
But while your thread is doing something try and call the thread property SomeText from the UI.
Your app WILL fall over.
This is the last thing you want for this app.

Like I said, trust me on this one, well no, in fact don't trust me, try it yourself. This will happen. You WILL get the "Switch To...Retry" error.

Your app cannot, and will not, be able to communicate with the thread UNTIL that loop has finished.
A very very quick fix would be do add DoEvents into the loop, but this is VERY VERY bad and can mess up certain code execution and leave things in memory. This should not be used.

Do you honestly think I would have spent all my time and effort in writting my vbGateway code if what you're suggesting is possible? I've been down that route and tried and tested it all many many times to perfect my vbGateway code.

Woka

----------


## lozware

Well yeah, thats kinda pointing out the obvious. A thread is just that... a thread. If any thread is busy (whether it was written in C++ or VB), then it wont respond. If you wanted to have the thread readable while performing a loop, then you would need to split that form up into 2 threads, one to do the Do While Loop, and one to host the properties (thats just plain common-sense).

Look at the attached file. open it up, and compile the EXE. It creates threads that go into Big DO WHILE loops, and reads from them at the same time!!!

----------


## Wokawidget

I don't need to create another thread to read from mine.
I don't have VB6 on this PC, but I've looked at your code, and it's like what I said.
It's almost multithreading, but like I said, it will fall over if you try to make a call to the thread when it's doing something.
This imo is a fundamental floor and is therefore not multithreading.

The last thing you want to for this app to be running on the server and for you to run into these problems.

Seriously, I know what you're trying to do, and I know it "almost works", but it's just not good enough for a server app imo as you cannot make calls to a thread that is doing something.
In VB.NET and c# you can make calls to a thread that is doing something.

VB6 does NOT do true proper multithreading, regardless of what people say, it's impossible in VB6. The ONLY way around this is to use code that I have written.
Yea, there are many variations on this, which you have found, but they are not as good as the code I wrote as I can call into a thread that is working and my app won't hang, or show that "Switch to" error due to the way I have coded how the UI and thread interact with each other. This is where all my work and dev time went into, to get around this issue of calling a working thread.

Use your code if you want, but bear in mind that it only 1/2 simulates multithreading and you will/may have issues when trying to communicate with a working thread.

Woof

Woka

----------


## lozware

IMO I prefer my method. If you need to read a property from the busy thread, then make a new thread to do so... like I said, it makes sense. If you actually run the compiled EXE of the project I attached, you will actually see just one process in the task manager, and each time you press the 'Create New Thread' button, the thread number will go up for that process (you need to go _View> SelectColumns > Threads_ to see this). So to be honest, I would class this as real multithreading... 1 process... multiple threads... what else does it need to do in order to classify as multithreading?!?

However, on your program all it does is create multiple processes, and link them together via a DLL - which is far from multithreading, and it means that you are very limited in what you can do (like passing Connection Requests from Winsockets). Apart from the Winsock limitation, you are also burning up huge amounts of memory.

----------


## Wokawidget

Hahaa. Ok. fair enough. We will have to disagree to agree on this one.
But one of the main points regarding multithreading is being able to make calls to it while it's busy  :Wink: 

I don't need to compile and see your code. I've seen the same thing a million squillion times before. I did exactly what u have done when I 1st started out doing this...it's not new code, it's all over the web. However, I absolutely 100% needed to be able to call into that thread to get access to functions just as "CloseConnection" regardless if it's doing something or not. You cannot do this, even with your use of another thread. Your code WILL crash here I am afraid.
If you close your main UI app down while you have many threads open, and u don't call CloseThread function in the thread then because you are using hidden forms I believe this will cause a memory leak.

I have done this code a million times over many numbers of years and have seen the pro's and conn's of all methods.

Woka

----------


## lozware

I still think you should give it a go, you havent seen it running yet. I know you have seen the code in the ZIP file, but unless you are either super-naturally clever, or have some sort of built-in VB compiler in you head, then you CANT picture it working without compiling it and running it.  :Thumb: 

EDIT:
And apart from anything, its just rude. It took me 30 mins to put the first lot of code up here, and another 30 mins to write the test project (which was tailor made for you).

----------


## si_the_geek

Like many long-term members here, Woka is capable of knowing how code will work by just reading the code.  When you have lots of programming experience, you dont need to compile code to know what it is doing, or (roughly) how efficiently it will do it.

As far as (simulated) multi-threading for VB6 goes, I've never come across anyone with as much knowledge as Woka.  

As far as writing of the code for his benefit, there wasnt really any point I'm afraid - as he had mentioned that he'd already done something similar.  It was presumably a learning experience for you tho, so it's not that bad.   :Wink:

----------


## lozware

Right - I am sorry, but I wasn't aware that my knowledge in VB and multithreading was reflected in my post-count.

si_the_geek:
Don't patronise me.

Wokka:
Good luck with your code, but I will use mine thanks - and it is working very well.

----------


## si_the_geek

I didn't mean it to be patronising, I'm sorry it came across that way.  I never mentioned anything about your post count - I have never seen someone with as much knowledge as Woka on this subject, even after some serious searching the web for alternatives.

I can see from what you have posted that you have good knowledge of it too (probably better than me), but that doesn't change the fact that Woka's view comes from lots experience, and his analysis is likely to be correct.  If your code works for you tho, that's great.  I'm sure others will be able to learn from it.  :Smilie:

----------


## Wokawidget

I have no problem at all with you shunning my code, your code to be fair deals with the RequestID of winsock much better than mine does, which is a big bonus in your case, but my code handles calling into the thread much much better than yours. It's a trade off of what you want in your app. I was just trying to make you aware that you may run into issues with your threads.

Si wasn't patronising you in the slightest. The code you have posted on here is very simple, and like Si mentioned, I don't need a compiler to see how it runs, I can just view the raw code in notepad. I am sorry you took his comments that way  :Frown: 

I am doing consultancy work in Norway at the moment, and don't have VB6 on my lappy, nor do have have direct access to the VB6 install CD's. I do at home though.
If I did have VB6 I would have compiled your code, modified it slightly and reposted it to show exactly what I have been getting at. Just for reference purposes mind you.

Your code, although it runs in seperate threads quite happily, is missing quite a lot of "important" multithreading capablities/functionality, which if you don't need then this is fine.

No one here takes your post count into concideration at all. Everyone has to start at a post count of 0 at some point, regardless of their programming skills.

Si was just trying to say that some ppl don't need to compile and test code to see how it works, so it's not rude of me really, which I think Si was trying to point out. I would if I had VB6, but then again, I would gain no extra benefit from compiling and testing your code, unless I was going to modify it and post it back to you...even then, notepad would suffice to a certain extent.

Trust me, no one is insulting your intelligence...

woka

----------


## Kaushikkale

I have gone through your code for multithreading. It is indeed a very good code. I came across your codes when searching for multithreading with VB6. 

I was not aware of a proper method to do multithreading in VB6 so I chose to use VB.NET to do multithreading. 

In my application, I use two threads in the single application. One thread is used to run the main process. While the process is running in background, a form is displayed with a button STOP for stopping the process. As soon as the user presses the STOP button, the first thread running the main process is terminated. 

This is easily achievable in VB.NET. Can this be done taking help of your code.

Kaushik Kale.

----------


## Wokawidget

Yes this is easily do-able in .NET, ver y easy.
And yes, my code can do what you've described.
Just create 2 thread sin the UI app.

WOka

----------


## hanysaad

Thank you !!!
very nice !

----------


## Jay Rogozinsky

> No it's not


Yes it was :-)




> U honestly think I went to all that trouble to write multithreading code if it were that simple


You *did not* write multithreading code ... you wrote a messaging front end.

In fact, your sample code is NOT (I repeat NOT) multithreading .... it's multiple processes.  My dear friend, they are not the same things!




> This is where my code comes in  I can communicate with the ActiveX EXE's regardless if they are busy or not, and vis versa. Using your method you cannot.


No, you can not!  A busy thread is a busy thread!  *** What YOU DO MEAN is that the caller won't BLOCK. ***

Your just avoiding the block by avoiding the interface (which is marshalled).

However, to be certain, you are NOT talking to a busy thread - assuming the thread is busy with something OTHER than your IPC mechanism.

I have looked at and tested you code.

With due respect:  Your using Windows Messaging for an IPC mechanism ... Yuch!

Sorry, but my IPC is way faster and doesn't eat the system.

I also noticed that after you start a couple seaches, your main form pukes and becomes unresponsive.




> Almost multithreading, but your code falls at the last hurdle. Trust me on this one.
> Woka


No, don't!

I was "harsh" - Iozware made valuable points which were overlooked.

What Woka has created is an IPC mechanism ... *not* multithreading.  Basically, using the Windows message system to avoid VB mashalling which kicks in when the public interface is called.

Woka, that's NOT mulithreading MAN!  You have an IPC.

THIS DISCUSSION has been about TWO topics which are being called one and the being confused

And yes, you can reliably INPROC multithread with VB6.

----------


## Wokawidget

Hmmmm. I am trying to find the thread where you have quoted me there. Can you link it.
The title of this thread has the word "Simulating" in it if you hadn't noticed, and I am fully aware it uses processes.

My main form is only a demo. And it's not that that's causing it to be unresponsive. You make silly abounts of calls to any UI and it'll become unresponsive. I did not code for that in the simple demo.

Woka

----------


## ididntdoit

I thought posting EXEs in your zips was prohibted?  :Confused:   :Stick Out Tongue:   :Ehh:

----------


## Chrisikins

Wokawidget:  Thank you for providing the protocols enabling the communication required for a sort of multithreading, although it would be nice to be able to have a common data source and proper multithreading within a single program as I used to be able to do when writing in Coral and Assembler.  

Perhaps I'm using the wrong language, but I've only recently returned to programming and haven't got round to learning C yet, although have written over 40,000 lines of VB in one project and nearly as much in my second.

Thanks.

Chris.

----------


## yonghan

Sir,how come the demoui doesn't work in my computer?It says that activex can't create object.Thanks a lot..

----------


## Merri

Have you compiled the DLL?

----------


## yonghan

I've compiled thee dll file..What should i fill in the extention textbox?Thanks

----------


## yonghan

Dear mr woka,is it possible to connect to other application too??Thanks a lot..

----------


## akhileshbc

@*Wokawidget*: Thanks a lot for this multithreading project...  :wave: 

I will try experimenting with it....  :Smilie:

----------


## OzWoz99

Although WokaWidget's multithreading code is quite old now, it is ideal for what I am doing  (spread a large VB6 number-crunching simulation across multiple processor cores).

Had it all working in the IDE and compiled, but then when I add a manifest file, the mobjgateway DLL immediately crashes with an error on SetWindowsLong

This problem is simple to reproduce with WokaWidgets vbGateway2\Demo\Project1 code. Just add a standard 'XP' manifest (as project1.exe.manifest containing the usual mscomctl assembly for XP look). Start up project1.exe and bingo - you get an error 'Unable to hook window', which is generated by SetWindowLong in sub HookWindow in mobjgateway.vbp

SO... Can anyone tell me what the manifest is screwing up and why? Then  point me at how to resolve it???

Thanks

(The original zip file is at http://www.vbforums.com/attachment.p...1&d=1089126436)

----------


## Wokawidget

Wow. Never seen than before.
I have never really done any work in anger with manifest files and vb6 I am afraid.
But why it should cause an error of that nature is a bit of a mystery.

Can you post a screen shot of the error...and the function, including all the functions lines of code, where this occured.

cheers,

woka

ps Glad you like it  :Smilie:

----------


## Wokawidget

While I do love my vbGateway code...it's a little bit outdated now thanks to .NET.
You know you can do in .NET in a few lines of code what this entire project does?

Woka

----------


## OzWoz99

Woka,

Here are the full details of the problem with vbGateway. I have stripped out all the code down to the bare minimum - even removing the .startlink

The test code



```
Option Explicit
Private WithEvents mobjGateway As Gateway
Private Sub Form_Load()
    Set mobjGateway = New Gateway
End Sub
```

Procedure: The attached zip file contains the vbp and also the manifest file. The second zip is the original Woka gateway code with vbGateway2

1. Compile vbGateway2 and register the dll

2. Compile SimpleDemo (after adding the wokawidget gateway reference of course)

3.  Now run SimpleDemo.exe and you will see -


This seems to be from vbGateway2 'HookWindow' -


```
Public Sub HookWindow(ByRef pobjGateway As Gateway)
Dim lngOldWndProc       As Long
    lngOldWndProc = SetWindowLong(pobjGateway.hWnd, GWL_WNDPROC, AddressOf WndProc)
    If lngOldWndProc > 0 Then
        pobjGateway.OldWndProc = lngOldWndProc
        If mcolItems Is Nothing Then
            Set mcolItems = New Collection
        End If
        mcolItems.Add ObjPtr(pobjGateway), CreateKey(pobjGateway.hWnd)
    Else
        Err.Raise vbObjectError, App.EXEName, "Unable to hook window."
    End If
End Sub
```

4. Now rename SimpleDemo.exe.manifest as, say, TTSimpleDemo.exe.manifest. Start SimpleDemo again - it works fine

5. Now put SimpleDemo.exe.manifest back again and edit SimpleDemo.vbp to remove the 'Set mobjGateway = New Gateway' statement. Compile and run again - it works fine as well. (By the way, the reason the 'DoesNothing' button is there is simply to show that the manifest is working and doesn't have an error (i.e. you see the XP-style button).

I have no idea why the manifest is screwing up the gateway - I always thought it simply forces use of the 6.0 version of MSCOMCTL (along with InitCommonControls in the code, which I have also stripped out in this test).

Help!!

----------


## Breathless

Hi
Im trying to test this code but when i open vbgateway2.vbp then i get this message in vb6:
Unable to set version compatible component: c:/program files/student works/common/compatible/vbgateway2.dll

How to fix it?

----------


## Nightwalker83

> Hi
> Im trying to test this code but when i open vbgateway2.vbp then i get this message in vb6:
> Unable to set version compatible component: c:/program files/student works/common/compatible/vbgateway2.dll


Try using the version in post 46 if the one in post #1 is causing the problem or vice-verse. If the source code of the dll is included recompile it with the version compatibility set to none. Save the project then recompile using "Binary Compatibility" using the previous dll you just created as the reference.

----------


## Breathless

> Try using the version in post 46 if the one in post #1 is causing the problem or vice-verse. If the source code of the dll is included recompile it with the version compatibility set to none. Save the project then recompile using "Binary Compatibility" using the previous dll you just created as the reference.


Hi thank you for interesting my problem.
The point is this error Message is appearing when i open source code of this dll. There are no compiled dll in this package. Other test projects in this package are opening but they require this dll. If i compile it althought this error message then using it as a reference i get actixeX error.

I done what you suggested but it dosnt help. There are still the same error. What can i else do?

----------


## Nightwalker83

Make sure you unselect the dll reference in the main projects (project that uses the dll) then save it and re reference the dll again.

----------


## Breathless

Good point thanks :Smilie:  now i can open and test project from /demo/ folder. It works great. But i still have problems with demos in /Multithreading/ folder.
DemoUi - there are still errors with activex obkect when i click search.
Set objsearch = CreateObject("searchThread.clsNewSearch")
This is highlighten

ThreadUI - no errors, but nothing happens when i Run this project.

What can i do to run it?

----------


## Breathless

Nobody? :Frown:

----------


## SDSInc

Well - over three years later your post helped me.  I had a manifest file which didn't take effect in the IDE so everything worked.  Outside the IDE - crash with the same message you mentioned.  I can live without the manifest!

----------


## wqweto

`If lngOldWndProc > 0 Then` in `HookWindow` code seems to be awfully wrong. Has to be `If lngOldWndProc <> 0 Then` for sure.

Whether this will fix issue with manifests is a separate question :-))

cheers,
</wqw>

----------

