Re: VB6 Threaded Forms (simple Demo)
Quote:
I have to, because this API is the only official way on a Win-OS, to create - well - a thread.
Any language who wants to establish an STA (on a new thread), has to call this API at some point.
Not only CreateThread.
Quote:
And no - FreeThreading (in the real sense) implies also cross-thread-sharing of (global) variables -
which I did not try to attempt (by hacking VB6 with regards to avoiding the built-in ThreadLocalStorage).
In your opinion, if we do not use global variables, then this turns out to be a non-free-threading? But free-threading means you can safe call the methods without marshaling across threads. The second question - who hacking TLS?
Quote:
You mean implicitely - via DoEvents (and its "hidden Sleep(0) call")?
Well, I've found - when developing/testing the (threaded) RPCserver-support in RC5 (decades ago) -
that a final Sleep(0) call in the "pump-loop" was increasing performance under heavy concurrent load.
So please read, what the MSDN has to say (about Sleep with Param 0) -
or alternatively this discussion:
https://stackoverflow.com/questions/...ance-of-sleep0
I mean there is much suitable way by using special Wait functions (like WaitForSingleObject).
Quote:
I've never said, that *everything* in your threading-modules was "a hack".
And in case you meant, I've "stolen something" - well, I didn't.
In the new Demo, I've restricted myself to "only the things which are known to be safe to use"
(especially when the whole STA-establishing stuff is encapsulated in a Dll, as in my example).
No-no. You (and others) can use my codes even don't mention me (i always told it). This isn't problem. I meant other. When i told you - "an user should know it" you answered "A VB6 beginner (or hobbyist) does not need to know (in detail) what an STA is, or how TLS works (underneath)."
If you would demonstrate the Mandelbrot example at the first post i didn't begin this discussion about learning because it would have no sense. Just what i told about you've implemented in the new example which is very good and useful. Just imagine if your first post was with this example do my following post have sense?
Quote:
I said, that the "interna of STAs" are not, what a User (of an STA-threaded solution) should "bother with".
What's the internal? I already wrote about that (MessagePump, Marshaling, etc.). This sounds very strange you made the example with that internal things and you told user shouldn't bother about that. How should an user go steps to StdEXE+DLL from AxEXE without that things?
Quote:
They are (black-box-like) hidden when the builtin AxExe-threading is used -
and they are "hidden in a Dll-binary", when StdExes want to use the same STA-based threading
(as shown in my example, or when using DirectCOM.dll from the RC5-package).
Again :rolleyes:. They aren't hidden in your example. When you need to perform an async task (the multithreadin is used for) you use this things and you need to know that things to avoid the typical threading errors like deadlocks, etc.
Re: VB6 Threaded Forms (simple Demo)
Quote:
Originally Posted by
The trick
Again :rolleyes:. They aren't hidden in your example. When you need to perform an async task (the multithreadin is used for) you use this things and you need to know that things to avoid the typical threading errors like deadlocks, etc.
I seriously don't know, why you're deliberately "playing dumb" in this thread (across so many postings).
Instead of "Step6" of this tutorial, I'd have personally preferred to just include a C-compiled "CreateWorkerObjectOnSTA_Helper.dll"
(or one, developed in FreeBasic, or C++, or FreePascal... meaning that those other languages would have offered an easier implementation-path, because they support FreeThreading out-of-the-box)
Such a "BlackBox"-binary (similar to DirectCOM.dll - which was implemented using PowerBasic - and does that kind of thing for nearly two decades now),
is the only thing needed, to "close the gap, to what MS already did implement - hidden - but sadly only for VB6-Apps in ActiveX-Exe-mode).
In both cases:
- AxExe-based new STA-Object-creation
- and "BlackBox-dll-based creation" of such STA-WorkerObjects,
the "bothersome details of STAs" will remain hidden from the User
(which is a good thing, because they only distract from what's really needed, to develop stable, STA-based VB6-threading-solutions).
I've included this Step6-Project as VB6-source only, because the Forum-rules forbid the upload of Dll-binaries.
The real thread-implementations in TutorialFolders Step-7 and 8 - are both using only the compiled version of Step6 (via a reference to ThreadedSTAs.dll).
And only in those 2 Projects (not in Step6) is, where "the real VB6-threading-stuff happens" (which plays by the rules of such WorkerObjects on STAs).
Olaf
Re: VB6 Threaded Forms (simple Demo)
Quote:
Instead of "Step6" of this tutorial, I'd have personally preferred to just include a C-compiled "CreateWorkerObjectOnSTA_Helper.dll"
(or one, developed in FreeBasic, or C++, or FreePascal... meaning that those other languages would have offered an easier implementation-path, because they support FreeThreading out-of-the-box)
Why should i use another language/additional dependency if i may use the same language? You've demonstrated it yourself. Why should i use "a black box" to achieve the task i can implement without it?
Quote:
In both cases:
- AxExe-based new STA-Object-creation
- and "BlackBox-dll-based creation" of such STA-WorkerObjects,
the "bothersome details of STAs" will remain hidden from the User
(which is a good thing, because they only distract from what's really needed, to develop stable, STA-based VB6-threading-solutions).
This isn't good thing. I've already wrote about that.
Quote:
I've included this Step6-Project as VB6-source only, because the Forum-rules forbid the upload of Dll-binaries.
You could refer to a dll/source code (developed in FreeBasic, or C++, or FreePascal). Hundreds of examples in codebank which refer to RC5. Does it bother you? Who are "playing dumb"? Let's tell about what you done not what you wanted.
I don't understand your position. You've created the example which teaches nothing. Just threading for threading. I've written about that and asked what could an user learn. You wrote the user couldn't know many things about STA-COM-threading. You called all other threading except your - bad/unstable/hacks/etc. But when you need the real threading things you use this things/unstable hacks. You tell me i'm "playing dumb" but I think it's not me.
Of course then you've written the real good threading example which is good for learning. If it would be originally I wouldn't start this discussion.
Re: VB6 Threaded Forms (simple Demo)
Quote:
Originally Posted by
The trick
I don't understand your position.
Deliberately so, I guess.
Quote:
Originally Posted by
The trick
You've created the example which teaches nothing.
Wrong, the two examples here (in this thread, are about AxExe-related threading),
and they do the same thing (showing Forms on their own threads), as discussed in other threads (using your helper-modules).
But with a significant difference:
- they use less code
- they are much more stable
And if that's not an advantage which should be "made known" (or "taught"), then I don't know what else this forum is for...
Quote:
Originally Posted by
The trick
I've written about that and asked what could an user learn.
And I've explained that to you already several times.
If a threading-solution is more stable - and uses less code than an alternative -
then it is clearly better - and the user should learn how to write threading-code for that better approach.
Quote:
Originally Posted by
The trick
You wrote the user couldn't know many things about STA-COM-threading.
No, I wrote that the user "doesn't need to know" (why STA-based threading works, as it works).
That's totally different from your "couldn't know" above.
Quote:
Originally Posted by
The trick
You called all other threading except your - bad/unstable/hacks/etc.
Well, that's because they clearly are (unstable hacks).
The main-point being:
- as soon as you "drag" thread-callback-code into a VB6-StdExe-Binary, your whole App.exe becomes "risky to run",
- especially when you enabled "global Variable sharing" along with these hacks
The only safe way to do threading in VB6 is:
1) to encapsulate your WorkerObject in a Public Class (and Public Classes are only possible in VB6's AxExe-, Dll-, and OCX-Projects, not in StdExes)
2) to place your Worker-Object on an STA (either via AxExes CreateObject-call, or via a compiled Helper-Dll when you do that from StdExe-code)
And whilst Krools threading-helper is breaking only rule #1) (halfways, via his Interface-callbacks),
your "threading-module helper" is breaking both of the above two rules...
In short - never, ever place VB6-based ThreadCallback-code directly within the Code-Modules of a StdExe.
Quote:
Originally Posted by
The trick
But when you need the real threading things you use this things/unstable hacks.
Nooo, I'm not doing that - I just wrote above, that the code which establishes a Worker-Object on an STA,
should be "hidden away in a binary" (in a compiled Dll).
In case of AxExes this "precompiled STA establishing code" is sitting in the vbRuntime-dll.
In case of StdExes this "precompiled STA establishing code" is sitting in ThreadedSTAs.dll.
The user should never include "editable (VB6)-Thread-Callback code" within his Executable-Project.
Only then will things run stable.
With your threading-helper *.bas module, you're outright encouraging Users,
to include this stuff into a StdExe-Project directly as Code.
Please don't do that - it's not stable - never was - and never will be (until a new compiler comes out).
Quote:
Originally Posted by
The trick
You tell me i'm "playing dumb" but I think it's not me.
Well, in the meantime I'm starting to think, that you "really don't get it".
Quote:
Originally Posted by
The trick
Of course then you've written the real good threading example which is good for learning.
If you're referring to the Mandelbrot-Tutorial, then this outright proves, that you understood nothing so far.
Because what I'm showing there, is exactly the same thing as I was showing here.
I'm establishing WorkerObjects on their own STAs (and show, how to work with them, "once they are there").
The only difference in the Mandelbrot-Tutorial is, that I made things more generic,
by introducing a cThreadHost- (+ cThreadPool) abstraction, which allows to instantiate these STA-WorkerObjects
(from any Ax-Dll) in a "non-specific, generic way" (via a ProgID to such an "outsourced" Ax-Dll-Class).
But the principle is the same - and very, very different from what you promote by: "just include my threadhelper.bas into your StdExes".
Olaf
Re: VB6 Threaded Forms (simple Demo)
can use vbheader for activex.exe threading bu api createthread。
if only use createobject("activexExe.class1"),You cannot use global variables, and they run very slowly.
Re: VB6 Threaded Forms (simple Demo)
Quote:
Originally Posted by
xiaoyao
can use vbheader for activex.exe threading bu api createthread。
As already stated several times, this is not recommended - and also not needed (in most VB6-threading-scenarios).
Quote:
Originally Posted by
xiaoyao
if only use createobject("activexExe.class1"),You cannot use global variables, and they run very slowly.
There's dozens of different ways to communicate in a faster manner among thread-STAs:
- shared Memory-areas via SafeArrays only being one of them
- there's also Pipes, Sockets, FileMapping, shared SQLite-InMem-DBs
- or just plain "pre-transfer of Input-Parameters via normal COM-marshaling into thread-locally reachable Variables"
Neither of the above methods will require you, to incorporate vbHeader-hacking into your "threaded VB6-solution".
Olaf
Re: VB6 Threaded Forms (simple Demo)
Quote:
Wrong, the two examples here (in this thread, are about AxExe-related threading),
and they do the same thing (showing Forms on their own threads), as discussed in other threads (using your helper-modules).
No. Those threads wasn't about just-create-a-form in thread the threads where you posted your example was about NativeDLL-callbacks.
Quote:
But with a significant difference:
- they use less code
- they are much more stable
And if that's not an advantage which should be "made known" (or "taught"), then I don't know what else this forum is for...
We saw how can it be more stable with the private user controls. The user code amount is the same, you don't need touch the helper module.
Quote:
If a threading-solution is more stable - and uses less code than an alternative -
then it is clearly better - and the user should learn how to write threading-code for that better approach.
I'm disagree. Decomposition to several projects isn't less code. The code wasn't about threading - you just created the objects in threads. No communication/no-async/no-advantages from threading.
Quote:
No, I wrote that the user "doesn't need to know" (why STA-based threading works, as it works).
That's totally different from your "couldn't know" above.
And i wrote that's bad and explained. The bunch of jsvenu's questions about free-threading/why we need to marshal/free-marshaller etc. about STA/MTA.
Quote:
Well, that's because they clearly are (unstable hacks).
http://www.vbforums.com/showthread.p...=1#post5447257
Quote:
The main-point being:
- as soon as you "drag" thread-callback-code into a VB6-StdExe-Binary, your whole App.exe becomes "risky to run",
- especially when you enabled "global Variable sharing" along with these hacks
I don't know your knowledge about vb-internals but i know something about it. The runtime manages all the projects and each project is associated with the special structure(structures). There is no significant difference between project types so if you have a properly initialized project you can use it.
You can use the shared-variables - this isn't violates COM rules.
Quote:
The only safe way to do threading in VB6 is:
1) to encapsulate your WorkerObject in a Public Class (and Public Classes are only possible in VB6's AxExe-, Dll-, and OCX-Projects, not in StdExes)
You can use also StdEXE classes.
Quote:
2) to place your Worker-Object on an STA (either via AxExes CreateObject-call, or via a compiled Helper-Dll when you do that from StdExe-code)
That's the base rule of COM regarding the single-threading apartments but you can't "place" and object to STA you can only create the object in an apartment.
Quote:
And whilst Krools threading-helper is breaking only rule #1) (halfways, via his Interface-callbacks),
your "threading-module helper" is breaking both of the above two rules...
No. My module doesn't break rule. It initializes STA apartment but it doesn't matter. Even if you initialize STA apartment you couldn't use a VB-class because you missed the other point related to runtime-initialization.
Quote:
In short - never, ever place VB6-based ThreadCallback-code directly within the Code-Modules of a StdExe.
Why? If need someone can use even non-initialized apartment/runtime. VB6 allows to mix procedural and OOP so we can use C-style coding. I already showed several stable examples of such behavior (like DirectShow, JuliaSet, EXE-Loader and Kernel-Driver (which don't use runtime at all)).
Quote:
Nooo, I'm not doing that - I just wrote above, that the code which establishes a Worker-Object on an STA,
should be "hidden away in a binary" (in a compiled Dll).
In case of AxExes this "precompiled STA establishing code" is sitting in the vbRuntime-dll.
In case of StdExes this "precompiled STA establishing code" is sitting in ThreadedSTAs.dll.
The user should never include "editable (VB6)-Thread-Callback code" within his Executable-Project.
Only then will things run stable.
No. It uses this "hacks". Your ThreadedSTAs.dll is written on VB6 which accepts the callbacks to ThreadProc. There isn't difference if you accept a callback to AxDll compiled function or StdExe compiled function.
Quote:
With your threading-helper *.bas module, you're outright encouraging Users,
to include this stuff into a StdExe-Project directly as Code.
Please don't do that - it's not stable - never was - and never will be (until a new compiler comes out).
Seems you don't know how does my module work. It works like AxEXE (it runs the code in the main thread when you debug like in AxEXE). It uses threading only when it's compiled.
Quote:
Well, in the meantime I'm starting to think, that you "really don't get it".
That's really. Just that's strange when you told - we shouldn't use free threading but you use that. When i told you about that you begin to tell me about "forum-rules" but hunderts-RC5-examples don't bother you. That's really strange. The my point is - yes we can use that (and your example shows that) and it works stable. Your point is incomprehensible.
Quote:
Because what I'm showing there, is exactly the same thing as I was showing here.
No. I already wrote if you would place Mandelbrod-example initially i didn't answer my question.
Quote:
I'm establishing WorkerObjects on their own STAs (and show, how to work with them, "once they are there").
The only difference in the Mandelbrot-Tutorial is, that I made things more generic,
by introducing a cThreadHost- (+ cThreadPool) abstraction, which allows to instantiate these STA-WorkerObjects
(from any Ax-Dll) in a "non-specific, generic way" (via a ProgID to such an "outsourced" Ax-Dll-Class).
You became to use the things which i told you about STA (message pumping/marshaling/etc), async calls, etc. That's the differences. Initially you told an user shouldn't know that.
Quote:
what you promote by: "just include my threadhelper.bas into your StdExes".
But this is real. Using my module you don't need to rewrite your application to decompose parts. It doesn't require SxS manifests (in the most cases). It doesn't require admin rights etc. Moreover the user can learn how does it work, how to do communication, how STA works, how Marshaling works, etc.
Re: VB6 Threaded Forms (simple Demo)
Quote:
Originally Posted by
The trick
You became to use the things which i told you about STA (message pumping/marshaling/etc), async calls, etc.
That's where our opinions differ (and we really should end this "talking in circles, repeating ourselves" soon).
Hopefully for the last time:
- You are of the opinion, that STA-establishing code should be used in a Std-Exe via a *.bas-module
- Whereas I advise strongly against that ... such STA-establishing code should be hidden-away in a separate "Black-Box-Dll"
- ... in the same way as it is "hidden from the User", when we use the "officially supported AxExe-based threading"
- ... so the User does not need to know exactly "why it works, as it works" (because it distracts from concrete Threading-implementations)
And no, it wasn't you who told me about "those things"
(I've written my first STA-establishing code as a VB6-helper-Dll already two decades ago).
Quote:
Originally Posted by
The trick
Initially you told an user shouldn't know that.
And I'm still of the same opinion - and have no clue, why you are incapable to understand this.
(despite the existence of my ThreadedSTAs-HelperDll, which should be considered a "don't look, don't touch it"-BlackBox,
which is only there - along with a few "extras" - to mimick the "official, built-in approach, as available in AxExes").
Proper VB6-supported Threading only requires you to know, how to "instantiate a Worker-(COM-)Object on a new thread".
That can be done in only one line of code (in both, the AxExe-based threading, and via the ThreadedSTAs-HelperDll).
Once you have this "ThreadObject", you "talk with the Worker-thread" through that (Worker-)Object.
(and that "marshaled" communication is automatically synchronized and "safe to use").
The only (slight) difficulty with that "official VB6-approach to threading" is -
hot to trigger asynchronous calls.
But this "async-problem" can be circumvented by dozens of different methods -
(the easiest one, is to use a simple, call-decoupling VB.Timer in your Worker-Object).
But that's basically all there is with regards to VB-Threading-basics "a User needs to know".
Quote:
Originally Posted by
The trick
Using my module you don't need to rewrite your application to decompose parts.
At the risk of making your whole StdExe-code instable, yes.
I also don't get, why "decomposing" (isolating) a "Thread-entity" in its own Dll(-Class) is a bad thing
(when it's just good engineering-practise).
E.g. Javascript follows a quite similar pattern (comparable to "VB6 STA-based threading") with its "WebWorkers":
- You can only establish such a WebWorker(Object) from a separate *.js-File
- You don't "share Variables" among Main- and Worker-Thread (the threads are memory-wise isolated from each other)
- You can only communicate with a WebWorker(Object) via Methods and Events, and Params are passed "as copies"
So this is quite comparable to the "isolation-level" and principles we have in VB6-STA-based threading.
And both threading-patterns have the same goal:
- to "make threading robust and more safe to use"
- for the "overwhelming majority of relatively inexperienced users of a higher-level language"!
I really don't get, why the VB6-community seems so obsessed with "Free Threading" - and "Variable-sharing",
when the designers were going out of their way, to offer a much safer to use threading-model in VB6.
Why not just use what's already there - why use instable hacks, when 99% of all threading-scenarios
can be covered with the "STA-based standard-approach to VB6-based threading"?
(and the 1% rest - by using Dlls, produced with "more suitable languages or -compilers").
Olaf
Re: VB6 Threaded Forms (simple Demo)
Quote:
And no, it wasn't you who told me about "those things"
(I've written my first STA-establishing code as a VB6-helper-Dll already two decades ago).
I meant you became use the things when you move from AxExe to StdEXE/AxDll decomposition. You claimed this is quite simple to move from AxExe to StdEXE/AxDll decomposition and an user shouldn't know about STA-internals at all. I claimed the user should know because it can face to some threading pitfails etc. like deadlocks, why use marshaling etc. These things are well documented and anyone who uses threading should know them. You told it's not needed. What i meant is you became use the things which you told aren't needed. So a potential user need to use those things if he doesn't want to use any "magic" dlls etc.
Quote:
Hopefully for the last time:
- You are of the opinion, that STA-establishing code should be used in a Std-Exe via a *.bas-module
- Whereas I advise strongly against that ... such STA-establishing code should be hidden-away in a separate "Black-Box-Dll"
- ... in the same way as it is "hidden from the User", when we use the "officially supported AxExe-based threading"
- ... so the User does not need to know exactly "why it works, as it works" (because it distracts from concrete Threading-implementations)
You could use a *.bas-module like a "Black-Box-Dll". You could use it "just-for-threading" as you advertised here. The advantage you can see and learn how does it work, change something, you don't depend on "Black-Box-Dll" developer, etc. Anyway after compilation there isn't difference if you call the compiled code either from a dll or compiled code from the exe.
Quote:
Proper VB6-supported Threading only requires you to know, how to "instantiate a Worker-(COM-)Object on a new thread".
That can be done in only one line of code (in both, the AxExe-based threading, and via the ThreadedSTAs-HelperDll).
You don't consider ThreadedSTAs-HelperDll code. You avoid this rule in that dll. Following your claims it can't be stable then, so all your ThreadedSTAs-HelperDll is unstable. Okay? But i don't think so. It's just your claims. Moreover by addition code from ThreadedSTAs-HelperDll and "instantiate a Worker-(COM-)Object on a new thread" we get more than one line of code.
By the way my module also supports this scenario (this is most part of code) (CreateActiveXObjectInNewThread/CreateActiveXObjectInNewThread2/CreatePrivateObjectByNameInNewThread). These functions also make marshaling things automatically the user shouldn't do it. In a word, the code does the same
Quote:
Once you have this "ThreadObject", you "talk with the Worker-thread" through that (Worker-)Object.
(and that "marshaled" communication is automatically synchronized and "safe to use").
The marshaling synchronization are implemented by COM (in our scenarios). This isn't difficult to talk about that.
Quote:
The only (slight) difficulty with that "official VB6-approach to threading" is -
hot to trigger asynchronous calls.
But this "async-problem" can be circumvented by dozens of different methods -
(the easiest one, is to use a simple, call-decoupling VB.Timer in your Worker-Object).
But that's basically all there is with regards to VB-Threading-basics "a User needs to know".
That's the main task in the 99% threading scenarios you didn't show in the initial example.
Quote:
At the risk of making your whole StdExe-code instable, yes.
I also don't get, why "decomposing" (isolating) a "Thread-entity" in its own Dll(-Class) is a bad thing
(when it's just good engineering-practise).
Because KISS principle. Why should i decompose if i don't need that? Just to use threading? No, thanks.
Quote:
E.g. Javascript follows a quite similar pattern (comparable to "VB6 STA-based threading") with its "WebWorkers":
- You can only establish such a WebWorker(Object) from a separate *.js-File
- You don't "share Variables" among Main- and Worker-Thread (the threads are memory-wise isolated from each other)
- You can only communicate with a WebWorker(Object) via Methods and Events, and Params are passed "as copies"
So this is quite comparable to the "isolation-level" and principles we have in VB6-STA-based threading.
Why did you give JS? I can give an example in C++ where you can use std::thread or _beginthread without any decomposition.
Quote:
I really don't get, why the VB6-community seems so obsessed with "Free Threading" - and "Variable-sharing",
when the designers were going out of their way, to offer a much safer to use threading-model in VB6.
The problem is you think the community shouldn't use those things but they actually need. You even suggested to use shared memory areas/file-mapping etc couple posts ago though now you tell we shouldn't use that shared things.
Re: VB6 Threaded Forms (simple Demo)
Yeah, as amusing as it was reading this debate over the pros and cons of each threading model, I do have a question pertaining to the initial post. Having to click a button to create new threads is obviously not very practical.
I discovered the hard way that moving the thread creation code in the "Form_Load" event doesn't work! It doesn't produce any errors but all the new forms display the same ThreadID, meaning they are not running in separate threads. A temporary fix was using the "Form_Activate" event instead but I was wondering if there's a better way?
Re: VB6 Threaded Forms (simple Demo)
Quote:
Originally Posted by
VanGoghGaming
...moving the thread creation code in the "Form_Load" event doesn't work!
That's a "known problem" with this "CreateObject(AxExe.Class)"-based STA-establishing...
At the point of Form_Load (of the first loaded VB-Form on the MainThread),
the vbRuntime is not yet in "the right state", that new threads(ThreadObjects) can be started this way.
A "OneShotTimer"(Event) would be a robust way to decouple the thread-startups from inside a Form_Load-Handler.
(though PostMessage-based decoupling should work also).
But yes, the Form_Activate Event is a "sufficiently late Event" to do so as well -
and matches with the "Keep it simple and API-free" intent of this CodeBank-entry the best.
I've uploaded this, so that others can make their first experiments with STA-based Thread(Objects).
For those who "want to get more serious" with STAs, I've uploaded a more advanced tutorial here:
https://www.vbforums.com/showthread....rot-Rendering)
Olaf
Re: VB6 Threaded Forms (simple Demo)
Yep, I've gathered as much. The good old "Timer" control gets the job done in a pinch. The "Form_Activate" event does exactly the same thing with the only caveat that it needs a "static" boolean variable to make sure it doesn't fire more than one time.
Also I'm a little bummed out that you have to use "CreateObject" versus the "New" keyword when creating new threads. All I could find online was that the former method is called "late bound" while the latter is called "early bound" and that doesn't explain much... I've always used "New" when creating objects so far.
I'll make sure to go through your Mandelbrot tutorial as well since it looks like a fun and enlightening experience.
Re: VB6 Threaded Forms (simple Demo)
Quote:
Originally Posted by
VanGoghGaming
I'm a little bummed out that you have to use "CreateObject" versus the "New" keyword when creating new threads.
This kind of thing plays into the realm of "regfree Object-instantiation"...
The CreateObject-call is a "VB-simplified outer wrapper" around the CoCreateInstance-API
(which itself is a wrapper around registry-lookups, typelib-interaction and COM-Threading-inits before the real instancing takes place),
whereas the New Keyword is more "near to the metal" in, that it bypasses all the registry-, typelib- and thread-init parts
(to jump "more straight" into the final phases of Instance-creation via a precompiled ClassFactory...)
That's the reason why CreateObject has to be used instead of New in this case of "InProcess Ax-Exe-Threading".
In the tutorial you're about to read, "all the stuff which CreateObject does under the covers" (in case of Ax-Exe-based STAs), will be done "manually" when you come to the parts which cover the "Dll-based STA-creation from within Std-Exes".
Olaf
Re: VB6 Threaded Forms (simple Demo)
I would like to have a New method written in VB6, to have it in M2000 Interpreter, which finally use CoCreateInstance-API. I think about to have the same list as the reference list in Vb6 and simply get a name from there. Also I would like to have the properties and methods and the events in a list, with parameter types.
Re: VB6 Threaded Forms (simple Demo)
Quote:
Originally Posted by
Schmidt
In the tutorial you're about to read...
Olaf
Finally got the time to go through your tutorial, it's very well put together and quite accessible to everyone. I especially like the way you send the WM_MOUSEMOVE message to a hidden form in order to get asynchronous execution, it's brilliant in its simplicity! I'm definitely gonna steal that, so much more elegant than using a Timer control! :D
Around step 5, where you introduce the "cThreadPool" class, I was mislead by its name. Initially I though you changed the "Threading Model" to "Thread Pool" in project properties and I was curious how you got that working because it was always crashing horribly when I tried it. But I see that was not the case, the "Threading model" is still set to "Thread per Object", haha!
This "cThreadPool" class is just a collection of thread objects used to gather them all under a single event. It's an interesting approach for sure. Instead of a collection, I've always used an array of thread objects for the same purpose in my projects and used "Implements" with a callback interface to gather them all by their "array index" under a single event.
I've got a question about the events raised by the worker threads. Assuming that all threads finish their calculations roughly at the same time, one would assume the threads would fire their "AsyncJobFinished" events roughly at the same time. So how is the main form (where you perform the actual drawing of the fractal) dealing with these events? Are they "queued" somehow in an invisible "event queue" and the main form is executing them sequentially as soon as they arrive?
Re: VB6 Threaded Forms (simple Demo)
Quote:
Originally Posted by
VanGoghGaming
Assuming that all threads finish their calculations roughly at the same time,
one would assume the threads would fire their "AsyncJobFinished" events roughly at the same time.
So how is the main form (where you perform the actual drawing of the fractal) dealing with these events?
Are they "queued" somehow in an invisible "event queue" ...
Yes, all Method- (and RaiseEvent-)calls which go to a COM-Class-instance on a different STA,
are automatically "serialized in a Msg-Queue" under the covers (so that these cross-thread calls are "synchronous").
That's the beauty of the COM-STA-based threading-model, since the User can rest assured, to "automatically work collision-free" -
without having to manage "synchronization himself" (via other means, like CriticalSections or Mutexes).
The disadvantage of this is (when all cross-thread calls are synchronous),
that one has to "trigger desired asynchronous behaviour" from within the "Callee-Class-Method" itself
(which in the examples is done via that PostMessage-decoupling you mentioned).
Olaf
Re: VB6 Threaded Forms (simple Demo)
Yep, all makes sense now. I see that in the last two steps of the tutorial you jump through a lot of hoops to make threading work for a "Standard EXE" instead of ActiveX. I was thinking it would be a lot easier that instead of using an "ActiveX DLL" for the "cMandelbrot" class, you could move it in an "ActiveX EXE" along with the "fAsyncHelper" form.
Then a "Standard EXE" would have no problem instantiating any number of objects from a single "ActiveX EXE" and managing their events out-of-the-box, no tricks required. One difference is that the worker objects would exist in their own process (visible in Task Manager) instead of their own thread, other than that the existing tutorial should work exactly the same without any modifications. I remember reading somewhere that "cross-thread" marshalling and "cross-process" marshalling have roughly the same cost (performance-wise).
The only other difference I can think of would be that "ActiveX EXE" objects can't be used "RegFree" like an "ActiveX DLL" but they do register themselves on the first execution...
Re: VB6 Threaded Forms (simple Demo)
Quote:
Originally Posted by
VanGoghGaming
I see that in the last two steps of the tutorial you jump through a lot of hoops -
to make threading work for a "Standard EXE" instead of ActiveX.
Might look this way, but once the "ThreadedSTAs.dll" was compiled,
you won't have to bother with that step ever again, and "just use it"
(it was written generically, and can instantiate any COM-Dll-Object on an STA as an "async Worker")
For example, if you want to perform a larger Folder-Backup "threaded, in the BackGround" -
the following Code could be used (when ThreadedSTAs was included as a Reference):
Code:
Option Explicit
Private WithEvents ThFSO As cThreadHost
Private Sub Form_Load()
'Set ThFSO = RegFree("ThreadedSTAs.cFactory").ThreadHost 'alternatively, if modManifest.bas is in the Project
Set ThFSO = CreateObject("ThreadedSTAs.cFactory").ThreadHost
ThFSO.CreateWorkerObject "Scripting.FileSystemObject"
End Sub
Private Sub Form_Click() 'async, threaded call into the FSO.CopyFolder-method
ThFSO.CallAsync "CopyFolder", "C:\Code", "D:\Backups\Code"
End Sub
Private Sub ThFSO_AsyncJobFinished(ByVal JobKeyCounter As String, ByVal Result As Variant, ByVal ErrString As String)
If Len(ErrString) Then MsgBox ErrString: Exit Sub
Debug.Print "Backup Finished", JobKeyCounter, Result
End Sub
Private Sub Form_Unload(Cancel As Integer)
ThFSO.Cleanup
End Sub
Quote:
Originally Posted by
VanGoghGaming
The only other difference I can think of would be that "ActiveX EXE" objects can't be used "RegFree"...
Yep, they don't work "Regfree, out of the box" ...
(since for proper registering, one would need to start them at least once, in "Run As Admin"-mode)
Olaf