-
The easiest way of multithreading
I've found this example, but I still don't understand it quite well because it's not commented, so I don't have a clue how to interact with the each thread and terminate all of them when I want to stop the process by closing the program or clicking on some "Stop" button. I don't want to do the creation of the external process or to call external file (DLL/EXE) or to use some complex classes/hacks, all I want is a simple multithreading which is almost ideal to the example that's mentioned above. Is that achievable i.e. is that project fixable or it has some flaws that can't be easily resolved?
My goal is to create asynchronous operations (timers) which will not freeze the UI - so the threading will be the solution.
-
Re: The most easiest way of multithreading
Simple Multithreading with VB6 would be considered an oxymoron ;)
If you don't want to use an ActiveX EXE then throw away the word simple. Though not sure multithreading + VB6 can ever be termed simple. Any other method may require an external DLL and/or some serious hacks.
From the link you posted and the comments therein, doesn't that project create additional processes vs. threads?
If multithreading with VB6 was simple, you'd find 10s of thousands of examples posted all over the web. Wish it was easy.
-
Re: The most easiest way of multithreading
-
Re: The most easiest way of multithreading
Quote:
Originally Posted by
LaVolpe
Simple Multithreading with VB6 would be considered an
oxymoron ;)
If you don't want to use an ActiveX EXE then throw away the word simple. Though not sure multithreading + VB6 can ever be termed simple. Any other method may require an external DLL and/or some serious hacks.
From the link you posted and the comments therein, doesn't that project create additional processes vs. threads?
If multithreading with VB6 was simple, you'd find 10s of thousands of examples posted all over the web. Wish it was easy.
I know that it's not simple, but that man did it a lot simpler than all examples that I've found.
I didn't linked to the main post, I've linked to the comment in that topic where is attached another project which I'm talking about.
-
1 Attachment(s)
Re: The most easiest way of multithreading
Okay, here it is. Solid as rock with minimal code and hacking ;)
BTW. I saw that this self-hosted ActiveX EXE approach was also presented by Olaf (Schmidt), but I didn't understood his code because it was created to calculate and draw fractals, so it was pretty complicated.
UPDATED #2:
-
1 Attachment(s)
Re: The most easiest way of multithreading
Hello MikiSoft. Specially for you I made this example. This is the usual project - StandartEXE. Take here the type library and read the description. Quite simply, instead of CreateThread are using vbCreateThread. Thread draws fractal. The main thread is used for the GUI.
Form:
Code:
Option Explicit
Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
Private Declare Function ColorHLSToRGB Lib "shlwapi.dll" (ByVal wHue As Integer, ByVal wLuminance As Integer, ByVal wSaturation As Integer) As Long
Dim hThread As Long
Dim di As Single
Dim dr As Single
Dim re As Single
Dim ie As Single
Private Sub Form_Load()
Dim i As Long
' Create palette
For i = 0 To 99
SimpleMultithreading.Palette(i) = ColorHLSToRGB(i * 2.42, 120, 240)
Next
' Set viewport
iLeft = -1
iRight = 1
iTop = -1
iBottom = 1
Randomize
' Set finish value
re = Rnd * 2 - 1
ie = Rnd * 2 - 1
dr = (re - Real) / 40
di = (ie - Imaginary) / 40
Process = True
' Call function in a new thread
hThread = vbCreateThread(0, 0, AddressOf DrawJulia, ObjPtr(picDisp), 0, 0)
End Sub
Private Sub Form_Unload(Cancel As Integer)
Process = False
' Wait until thread ends
WaitForSingleObject hThread, -1
End Sub
Private Sub tmrFPS_Timer()
Me.Caption = Format(FPS, "\F\P\S 0")
FPS = 0
End Sub
Private Sub tmrInterpolation_Timer()
' Interpolation
Real = Real + dr
Imaginary = Imaginary + di
If Abs(Real - re) < 0.0001 Then re = Rnd * 2 - 1: dr = (re - Real) / 40
If Abs(Imaginary - ie) < 0.0001 Then ie = Rnd * 2 - 1: di = (ie - Imaginary) / 40
End Sub
Module:
Code:
Option Explicit
Public Type RGBQUAD
rgbBlue As Byte
rgbGreen As Byte
rgbRed As Byte
rgbReserved As Byte
End Type
Public Type BITMAPINFOHEADER
biSize As Long
biWidth As Long
biHeight As Long
biPlanes As Integer
biBitCount As Integer
biCompression As Long
biSizeImage As Long
biXPelsPerMeter As Long
biYPelsPerMeter As Long
biClrUsed As Long
biClrImportant As Long
End Type
Public Type BITMAPINFO
bmiHeader As BITMAPINFOHEADER
bmiColors As RGBQUAD
End Type
Private Declare Function SetDIBitsToDevice Lib "gdi32" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long, ByVal dx As Long, ByVal dy As Long, ByVal SrcX As Long, ByVal SrcY As Long, ByVal Scan As Long, ByVal NumScans As Long, Bits As Any, BitsInfo As BITMAPINFO, ByVal wUsage As Long) As Long
Private Declare Function GetCurrentThreadId Lib "kernel32" () As Long
Public iLeft As Double
Public iTop As Double
Public iRight As Double
Public iBottom As Double
Public Real As Double
Public Imaginary As Double
Public Process As Boolean
Public Palette(99) As Long
Public FPS As Long
' // Function draw fractal on the picturebox
Public Function DrawJulia(ByVal pic As PictureBox) As Long
Dim x As Double, y As Double, Sx As Double, Sy As Double
Dim pt As Long, Bits() As Long, bi As BITMAPINFO
Dim lx As Long, ly As Long
ReDim Bits(pic.ScaleWidth * pic.ScaleHeight - 1)
With bi.bmiHeader
.biBitCount = 32
.biHeight = -pic.ScaleHeight
.biWidth = pic.ScaleWidth
.biPlanes = 1
.biSize = Len(bi.bmiHeader)
.biSizeImage = pic.ScaleWidth * pic.ScaleHeight * 4
End With
Do While Process
Sx = (iRight - iLeft) / (pic.ScaleWidth - 1)
Sy = (iRight - iLeft) / (pic.ScaleHeight - 1)
x = iLeft: y = iTop
Process = Not Not Process
pt = 0
For ly = 0 To pic.ScaleHeight - 1: For lx = 0 To pic.ScaleWidth - 1
x = x + Sx
Bits(pt) = Palette(Julia(x, y))
pt = pt + 1
Next: y = y + Sy: x = iLeft: Next
SetDIBitsToDevice pic.hdc, 0, 0, pic.ScaleWidth, ly, 0, 0, 0, ly, Bits(0), bi, 0
pic.CurrentX = 0
pic.CurrentY = 0
pic.Print Format(GetCurrentThreadId(), "T\hrea\d #")
FPS = FPS + 1
Loop
End Function
' // Function return value Julia set
Private Function Julia(x As Double, y As Double) As Single
Dim Zr As Double, Zi As Double
Dim Cr As Double, Ci As Double
Dim tZr As Double
Dim count As Long
Dim r As Single
count = 0
Zr = x: Zi = y
Cr = Real: Ci = Imaginary
Do While count < 99 And r < 10
tZr = Zr
Zr = Zr * Zr - Zi * Zi
Zi = tZr * Zi + Zi * tZr
Zr = Zr + Cr
Zi = Zi + Ci
r = Sqr(Zr * Zr + Zi * Zi)
count = count + 1
Loop
Julia = count
End Function
Attachment 125371
UPDATE: Make only a compiled version.
-
Re: [RESOLVED] The most easiest way of multithreading
Thanks for the effort, but I've already solved my problem with simple approach above. I want to ask why ActiveX EXE is different than Standard EXE as it does not require manual registration process (unlike DLL or OCX)?
-
Re: [RESOLVED] The most easiest way of multithreading
ActiveX EXE requires registration and if there is no admin rights then it will not work.
-
Re: [RESOLVED] The most easiest way of multithreading
MikiSoft, you edited your first post to include a goal. Timers should never freeze up the UI. I am assuming you are not talking about the timers, but rather the code that is called/executed once your timer event is received? If that is not the case, maybe we should be asking why your timers are freezing up your UI?
-
Re: [RESOLVED] The most easiest way of multithreading
@The trick: I see now. That can be a problem, but in almost every project I include ActiveX components so Administrator rights will be definitely needed.
@LaVople: I'm creating an array of timers to do some operation, so on slower computers they can freeze the UI and slow down each other.
-
Re: [RESOLVED] The most easiest way of multithreading
-
Re: The most easiest way of multithreading
Can that be used for ActiveX EXE or not? If yes, can I have some example? Answer here, thanks.
-
Re: The most easiest way of multithreading
Quote:
Originally Posted by
MikiSoft
Okay, here it is. Solid as rock with minimal code and hacking ;)
BTW. I saw that this self-hosted ActiveX EXE approach was also presented by Olaf, but I didn't understood his code because it was created to calculate and draw fractals, so it was pretty complicated.
UPDATED:
I don't understand what is multi-threading about this. The threads only run one at a time.
-
Re: The most easiest way of multithreading
You must compile it and run, otherwise in the IDE it won't work.
-
Re: The most easiest way of multithreading
Quote:
Originally Posted by
The trick
Hello
MikiSoft. Specially for you I made this example. This is the usual project - StandartEXE. Take
here the type library and read the description. Quite simply, instead of CreateThread are using vbCreateThread. Thread draws fractal. The main thread is used for the GUI.
Form:
Code:
Option Explicit
Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
Private Declare Function ColorHLSToRGB Lib "shlwapi.dll" (ByVal wHue As Integer, ByVal wLuminance As Integer, ByVal wSaturation As Integer) As Long
Dim hThread As Long
Dim di As Single
Dim dr As Single
Dim re As Single
Dim ie As Single
Private Sub Form_Load()
Dim i As Long
' Create palette
For i = 0 To 99
SimpleMultithreading.Palette(i) = ColorHLSToRGB(i * 2.42, 120, 240)
Next
' Set viewport
iLeft = -1
iRight = 1
iTop = -1
iBottom = 1
Randomize
' Set finish value
re = Rnd * 2 - 1
ie = Rnd * 2 - 1
dr = (re - Real) / 40
di = (ie - Imaginary) / 40
Process = True
' Call function in a new thread
hThread = vbCreateThread(0, 0, AddressOf DrawJulia, ObjPtr(picDisp), 0, 0)
End Sub
Private Sub Form_Unload(Cancel As Integer)
Process = False
' Wait until thread ends
WaitForSingleObject hThread, -1
End Sub
Private Sub tmrFPS_Timer()
Me.Caption = Format(FPS, "\F\P\S 0")
FPS = 0
End Sub
Private Sub tmrInterpolation_Timer()
' Interpolation
Real = Real + dr
Imaginary = Imaginary + di
If Abs(Real - re) < 0.0001 Then re = Rnd * 2 - 1: dr = (re - Real) / 40
If Abs(Imaginary - ie) < 0.0001 Then ie = Rnd * 2 - 1: di = (ie - Imaginary) / 40
End Sub
Module:
Code:
Option Explicit
Public Type RGBQUAD
rgbBlue As Byte
rgbGreen As Byte
rgbRed As Byte
rgbReserved As Byte
End Type
Public Type BITMAPINFOHEADER
biSize As Long
biWidth As Long
biHeight As Long
biPlanes As Integer
biBitCount As Integer
biCompression As Long
biSizeImage As Long
biXPelsPerMeter As Long
biYPelsPerMeter As Long
biClrUsed As Long
biClrImportant As Long
End Type
Public Type BITMAPINFO
bmiHeader As BITMAPINFOHEADER
bmiColors As RGBQUAD
End Type
Private Declare Function SetDIBitsToDevice Lib "gdi32" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long, ByVal dx As Long, ByVal dy As Long, ByVal SrcX As Long, ByVal SrcY As Long, ByVal Scan As Long, ByVal NumScans As Long, Bits As Any, BitsInfo As BITMAPINFO, ByVal wUsage As Long) As Long
Private Declare Function GetCurrentThreadId Lib "kernel32" () As Long
Public iLeft As Double
Public iTop As Double
Public iRight As Double
Public iBottom As Double
Public Real As Double
Public Imaginary As Double
Public Process As Boolean
Public Palette(99) As Long
Public FPS As Long
' // Function draw fractal on the picturebox
Public Function DrawJulia(ByVal pic As PictureBox) As Long
Dim x As Double, y As Double, Sx As Double, Sy As Double
Dim pt As Long, Bits() As Long, bi As BITMAPINFO
Dim lx As Long, ly As Long
ReDim Bits(pic.ScaleWidth * pic.ScaleHeight - 1)
With bi.bmiHeader
.biBitCount = 32
.biHeight = -pic.ScaleHeight
.biWidth = pic.ScaleWidth
.biPlanes = 1
.biSize = Len(bi.bmiHeader)
.biSizeImage = pic.ScaleWidth * pic.ScaleHeight * 4
End With
Do While Process
Sx = (iRight - iLeft) / (pic.ScaleWidth - 1)
Sy = (iRight - iLeft) / (pic.ScaleHeight - 1)
x = iLeft: y = iTop
Process = Not Not Process
pt = 0
For ly = 0 To pic.ScaleHeight - 1: For lx = 0 To pic.ScaleWidth - 1
x = x + Sx
Bits(pt) = Palette(Julia(x, y))
pt = pt + 1
Next: y = y + Sy: x = iLeft: Next
SetDIBitsToDevice pic.hdc, 0, 0, pic.ScaleWidth, ly, 0, 0, 0, ly, Bits(0), bi, 0
pic.CurrentX = 0
pic.CurrentY = 0
pic.Print Format(GetCurrentThreadId(), "T\hrea\d #")
FPS = FPS + 1
Loop
End Function
' // Function return value Julia set
Private Function Julia(x As Double, y As Double) As Single
Dim Zr As Double, Zi As Double
Dim Cr As Double, Ci As Double
Dim tZr As Double
Dim count As Long
Dim r As Single
count = 0
Zr = x: Zi = y
Cr = Real: Ci = Imaginary
Do While count < 99 And r < 10
tZr = Zr
Zr = Zr * Zr - Zi * Zi
Zi = tZr * Zi + Zi * tZr
Zr = Zr + Cr
Zi = Zi + Ci
r = Sqr(Zr * Zr + Zi * Zi)
count = count + 1
Loop
Julia = count
End Function
Attachment 125371
UPDATE: Make only a compiled version.
Can't find project or library
tlsIndex = TlsAlloc()
-
Re: The most easiest way of multithreading
Quote:
Originally Posted by
MikiSoft
You must compile it and run, otherwise in the IDE it won't work.
OK, very nice.
-
Re: The most easiest way of multithreading
Quote:
Originally Posted by
jmsrickland
Can't find project or library
tlsIndex = TlsAlloc()
Quote:
Originally Posted by
The trick
Take
here the type library and read the description.
See type library in the reference thread.
What sense in this multi-threading? (I mean the ActiveX EXE) DoEvents in a loop many times slow. I understand This is needed to marshalling. Interactions are synchronous, then what meaning in that? If you need to get some sort of response from another thread I should wait.
-
Re: Reg-Free ActiveX EXE, possible?
@MikiSoft: You don't need reg-free COM activation for your ActiveX EXE if you know beforehand the relative path to this executable once the whole solution is deployed. Then you can just manually start it w/ CreateProcess/ShellExecute and it will automagically register its public class factories w/ CoRegisterClassObject in ROT.
Unfortunately VB6 out-of-processes servers try to autoregister some marshaling support on start-up and this fails with bizarre errors when the first user to start it is not an admin. So the answer is both yes and no, it cannot be done.
Here is another strategy that is very hard to be done with VB6.
cheers,
</wqw>
-
Re: Can ActiveX EXE be Reg-Free or run without Administrator rights?
Thanks wqweto for the answer! Has anyone from here tried to accomplish that strategy or something similar, in order to avoid VB6 servers to do the registration process? It really bugs me, even more now when you said that, if I understood correctly, Administrator rights aren't really needed to do the proper registration of the out-of-process COM object.
-
Re: Reg-Free ActiveX EXE, possible?
Quote:
Originally Posted by
wqweto
Unfortunately VB6 out-of-processes servers try to autoregister some marshaling support on start-up and this fails with bizarre errors when the first user to start it is not an admin. So the answer is both yes and no, it cannot be done.
I swear to God, ActiveX could be a real pain that threatens to drive one insane.
-
Re: Can ActiveX EXE be Reg-Free or run without Administrator rights?
Quote:
Originally Posted by
MikiSoft
... if I understood correctly, Administrator rights aren't really needed to do the proper registration of the out-of-process COM object.
No, you "understood" exactly incorrectly.
An ActiveX EXE is an out of process COM server, and a VB6 ActiveX EXE merely follows the ActiveX and DCOM specifications, which require self-registration. By their nature the keys must be registered globally, so elevated permission is required. In this context the "first run" can perform the required registration but it must be an elevated run.
If you really "need multithreading" you might consider whether or not you can use a worker process instead of a worker thread. Of course you'll need to choose an IPC mechanism and deal with synchronization.
But even then you can't write your "worker" code based on busy loops and blocking calls. If you do, the worker has no way to be responsive to something like a shutdown request from the main program.
If you take yourself out of that box (busy/blocking code) you may suddenly realize you never needed a worker thread in the first place.
-
Re: Can ActiveX EXE be Reg-Free or run without Administrator rights?
Quote:
Originally Posted by
dilettante
An ActiveX EXE is an out of process COM server, ...
The above line is of course right - but I catched it up, to maybe shift the focus again,
on what we have here (with regards to, what triggered the OPs question).
It's InProcess-Threading we talk about (by means of an ActiveX-Exe-Host, which
of course could also act as an OutOfProcess-Server - but in case of the OP is
never used in that mode).
The InProcess-STAs in this AxExe-Mode are created by (Process-internal) calls to
CreateObject("MyProject.cMyInternalPublicClass"), which (when properly registered)
will instantiate the ClassObject (according to the ProgID we used in CreateObject)
on a new STA which runs in the same Process as the CreateObject-Caller.
When the Object in question would be instantiated instead by: New cMyInternalPublicClass
then the instance is not being created on a new STA, but on the calling thread instead
(usually the Main-Thread - aka "normal Class-instantiation/communication").
Just for completeness (although it was already mentioned in this discussion) - when
running such an InProcessThreading AxExe-Project in the IDE, the just mentioned
CreateObject(ThreadClassProgID)-calls will not cause the creation of a new STA -
instead the behaviour is comparable to using the normal instantiation per New
(which allows for easier debugging).
So, we have a quite easy and comfortable way to use InProcess-Threading in VB6 -
but (as this thread shows) - the only "catch" is the requirement, that the ActiveX-
Exe in question needs to be registered on the target-machine, to perform its
InProcess-Threading as designed.
@the OP
The reason for that is, that communication among Objects on different STAs has to be
marshalled - and the systems COM-marshaller cannot make use of the Interface-Infos
which are already contained in the compiled VB-Executable - only the VB6-AxExe knows
about them (to be used when "Objects talk among themselves" on the Main-Thread) -
for transparent cross-STA-communication among Objects these Interface Infos for the
Proxy/Stub-pairs have to be additionally available in the registry (because that's where
the marshaller-APIs will search for them).
There's no easy way around it (with regards to "Setup-free deployment") - other than
giving the information to the potential User (either in a ReadMe - or in a small Popup-
Info-Message which is shown on first start) - that the first run of the executable
has to be done in elevated mode (per "Run as Administrator").
On subsequent runs this won't be necessary anymore - but it's still a nuisance
(that's why I do my Thread-stuff not in Public ActiveX-Exe-Classes, but in Public
Dll-Classes, since that approach allows "regfree instantiation on STAs").
Olaf
-
Re: Can ActiveX EXE be Reg-Free or run without Administrator rights?
Quote:
Originally Posted by
Schmidt
that's why I do my Thread-stuff not in Public ActiveX-Exe-Classes, but in Public
Dll-Classes, since that approach allows "regfree instantiation on STAs"
Can you give me some example of that approach which is like my project above, if one could be ever made to be simple like that? Also, thanks for the detailed explanation, I fully understand it now!
-
Re: Can ActiveX EXE be Reg-Free or run without Administrator rights?
Quote:
Originally Posted by
MikiSoft
Can you give me some example of that approach which is like my project above, if one could be ever made to be simple like that?
The "simplicity" will depend a bit on, whether you want to show Forms from within your Threads -
or if these Threads are meant as "invisible workers" only...
Though since you opened yourself up to the idea, to use ActiveX-Dlls
(relinquishing the "everything in one Exe"-approach), you will now
have to consider your regfree shipping with an additional \Bin\-Folder
in your Zip (instead of a zipped "single Exe").
Basically you now have 3 options (3 convenience-levels, if you want) - though
each requires at least the ActiveX-Dll which contains your Thread-Class.
1) - Anatolis (The Trick's) Dll-threading approach without any additional helpers:
\MyStd.exe
\..\Bin\MyActiveXThread.dll
2) - DirectCOM.dll based (DirectCOM.dll adding ~20kB to your Zip-Archives size)
\MyStd.exe
\..\Bin\MyActiveXThread.dll
\..\Bin\DirectCOM.dll
3) - vbRichClient5 based (RC5-BaseDlls adding ~2.3MB to your Zip-Archives size)
\MyStd.exe
\..\Bin\MyActiveXThread.dll
\..\Bin\DirectCOM.dll
\..\Bin\vbRichClient5.dll
\..\Bin\vb_cairo_sqlite.dll
I've ordered them already according to their comfort-level with regards to
the threading-implementation - though each of the above is able to cover
regfree deployment as a "portable App".
Before I write an example, I'd like to know which of the above modes you'd
prefer (e.g. if you can live with the RC5-dependency, since that would require
the least efforts on my end).
Olaf
-
Re: Can ActiveX EXE be Reg-Free or run without Administrator rights?
I would choose the first approach since it's the most comfortable way, and if forms can't be included then they are not needed (the reason I have included them into my project is for better understanding and for showing how it works live). Thanks in advance!
-
Re: Can ActiveX EXE be Reg-Free or run without Administrator rights?
Quote:
Originally Posted by
MikiSoft
I would choose the first approach since it's the most comfortable way,...
Ehm, to be more clear about that - when I mentioned that I ordered them according to their
comfort-level, I meant "increased comfort (coding-wise), the further you go down the list". ;)
To see examples for Tricks approach, you can already take a look here, and see if that suits your needs:
http://www.vbforums.com/showthread.p...-in-VB6-part-1
or
http://www.vbforums.com/showthread.p...-of-Native-DLL
Olaf
-
Re: Can ActiveX EXE be Reg-Free or run without Administrator rights?
The first method with ActiveX DLL seems to be easier but I don't understand how to implement that into my project, it's a sensitive job since it's working directly with CLSIDs and COM API calls. But it will definitely be the best solution for this problem (if it really doesn't need to be run with Administrator privileges).
-
Re: Can ActiveX EXE be Reg-Free or run without Administrator rights?
Quote:
Originally Posted by
MikiSoft
The first method with ActiveX DLL seems to be easier...
You're kidding right ?
-
Re: Can ActiveX EXE be Reg-Free or run without Administrator rights?
Umm no? Why on the Earth would be a second method easier, since it works with native DLL which can't be made using VB6 without some hacking around...
-
Re: Can ActiveX EXE be Reg-Free or run without Administrator rights?
I think @trick had a sample of multi-threading with *standard* executable -- no AxEXE, no dlls.
cheers,
</wqw>
-
Re: Can ActiveX EXE be Reg-Free or run without Administrator rights?
Sorry for my bad English. :blush:
Quote:
Originally Posted by
MikiSoft
The first method with ActiveX DLL seems to be easier but I don't understand how to implement that into my project, it's a sensitive job since it's working directly with CLSIDs and COM API calls.
You can use the CreateObject. I wrote there.
Quote:
Originally Posted by
MikiSoft
Umm no? Why on the Earth would be a second method easier, since it works with native DLL which can't be made using VB6 without some hacking around...
I created the opportunity multithreading in a standard EXE. This is almost a complete analog CreateThread and _beginthread. Why not use it?
-
1 Attachment(s)
Re: Can ActiveX EXE be Reg-Free or run without Administrator rights?
Quote:
Originally Posted by
The trick
You can use the CreateObject. I wrote there.
Can you make a minimalist example using that command? I have now attached my project, splitted into Standard EXE and ActiveX DLL, so you can work with that.
-
Re: Can ActiveX EXE be Reg-Free or run without Administrator rights?
I'll write you later. I'm at work now.
-
Re: Can ActiveX EXE be Reg-Free or run without Administrator rights?
Bump - have you done that? I want my project above to be modified so I would know the differences and better understand it.
-
Re: Can ActiveX EXE be Reg-Free or run without Administrator rights?
Wait for the response on Monday, as I do not have access to a computer (I'm writing from the phone)
-
Re: Can ActiveX EXE be Reg-Free or run without Administrator rights?
So this thread's question was actually resolved back in post #4.
Sounds like everything else should have been split off and moved back to the original thread.
-
Re: Can ActiveX EXE be Reg-Free or run without Administrator rights?
Quote:
Originally Posted by
dilettante
So this thread's question was actually resolved back in post #4.
Sounds like everything else should have been split off and moved back to the original thread.
I was thinking the same, it need to be reported to moderators.
Quote:
Originally Posted by
The trick
Wait for the response on Monday, as I do not have access to a computer (I'm writing from the phone)
OK, I'll wait.
-
1 Attachment(s)
Re: Can ActiveX EXE be Reg-Free or run without Administrator rights?
Hello. As I promised (slightly delayed).
The first example - using multi-threading ActiveX DLL.
Create a new project ActiveX DLL. Create a new class Thread.cls.
Code:
Public Event ThreadFinished()
Public Property Get ThreadID() As Long
ThreadID = App.ThreadID
End Property
Public Function GetValue() As Long
GetValue = frmThread.GetValue()
End Function
Sub ShowFormWithCalculation(Key As String)
frmThread.Caption = Key
frmThread.Show vbModal
RaiseEvent ThreadFinished
End Sub
The class has an event ThreadFinished, which is generated when the calculation is finished. GetValue method gets the current value of the counter. Method ShowFormWithCalculation starts calculation.
Form code frmThread.frm
Code:
Dim abort As Boolean
Dim value As Long
' // Get calculated value
Public Property Get GetValue() As Long
GetValue = value
End Property
' // Long-long process
Public Sub RunCycle()
Do Until abort Or value = 150000
lblNum.Caption = Format(value, "000000")
lblNum.Refresh
value = value + 1
If (value And &HFF) = 0 Then DoEvents
Loop
Unload Me
End Sub
Private Sub cmdRun_Click()
RunCycle
End Sub
Private Sub Form_Unload(Cancel As Integer)
abort = True
End Sub
Ok. You're asked to do, like the above code. It would be easier not to use the form.
Consider a client application.
Standart module modMain.bas:
Code:
' modMain.bas - main module
' © Кривоус Анатолий Анатольевич (The trick), 2015
Option Explicit
Public Type UUID
Data1 As Long
Data2 As Integer
Data3 As Integer
Data4(0 To 7) As Byte
End Type
Public Declare Function GetMem1 Lib "msvbvm60" (Src As Any, Dst As Any) As Long
Public Declare Function GetMem4 Lib "msvbvm60" (Src As Any, Dst As Any) As Long
Public Declare Function VirtualProtect Lib "kernel32" (ByVal lpAddress As Long, ByVal dwSize As Long, ByVal flNewProtect As Long, lpflOldProtect As Long) As Long
Public Declare Function GetModuleHandle Lib "kernel32" Alias "GetModuleHandleW" (ByVal lpModuleName As Long) As Long
Public Declare Function GetProcAddress Lib "kernel32" (ByVal hModule As Long, ByVal lpProcName As String) As Long
Public Declare Function CreateThread Lib "kernel32" (lpThreadAttributes As Any, ByVal dwStackSize As Long, ByVal lpStartAddress As Long, lpParameter As Any, ByVal dwCreationFlags As Long, lpThreadId As Long) As Long
Public Declare Function CoInitialize Lib "ole32" (pvReserved As Any) As Long
Public Declare Function CoUninitialize Lib "ole32" () As Long
Public Declare Function CoMarshalInterThreadInterfaceInStream Lib "ole32.dll" (riid As UUID, ByVal pUnk As IUnknown, ppStm As Long) As Long
Public Declare Function CoGetInterfaceAndReleaseStream Lib "ole32.dll" (ByVal pStm As Long, riid As UUID, pUnk As Any) As Long
Public Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
Public Declare Function SetEvent Lib "kernel32" (ByVal hEvent As Long) As Long
Public Declare Function ResetEvent Lib "kernel32" (ByVal hEvent As Long) As Long
Public Declare Function CreateEvent Lib "kernel32" Alias "CreateEventW" (lpEventAttributes As Any, ByVal bManualReset As Long, ByVal bInitialState As Long, ByVal lpName As Long) As Long
Public Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Public Declare Function IIDFromString Lib "ole32" (ByVal lpsz As Long, lpiid As UUID) As Long
Public Const PAGE_EXECUTE_READWRITE As Long = &H40&
Public Const INFINITE As Long = -1&
Public Const IID_IUnknown As String = "{00000000-0000-0000-C000-000000000046}"
Public Type ThreadData
hEvent As Long ' Synchronization object
IStream As Long ' Stream object receiving a pointer of marshal-object prjSMT.Thread
key As String ' Parameter of method ShowFormWithCalculation
End Type
' // Remove crashes of Declared-functions, sacrificing Err.LastDllError
' // If used tlb for API-call, then not used.
Public Sub RemoveLastDllError()
Dim hMod As Long
Dim lpProc As Long
' Get function address __vbaSetSystemError
hMod = GetModuleHandle(StrPtr("msvbvm60"))
lpProc = GetProcAddress(hMod, "__vbaSetSystemError")
' Make "ret" opcode
VirtualProtect lpProc, 1, PAGE_EXECUTE_READWRITE, 0
GetMem1 &HC3, ByVal lpProc
End Sub
' // Thread
Public Function ThreadProc(value As ThreadData) As Long
Dim obj As prjSMT.Thread
Dim iid As UUID
' Initialization of COM
CoInitialize ByVal 0&
' Createing object - prjSMT.Thread
Set obj = CreateObject("prjSMT.Thread")
IIDFromString StrPtr(IID_IUnknown), iid
' Make marshalling
CoMarshalInterThreadInterfaceInStream iid, obj, value.IStream
' Initialization success
SetEvent value.hEvent
' Call method
obj.ShowFormWithCalculation value.key
' Remove object
Set obj = Nothing
' Uninitialize
CoUninitialize
End Function
Form with controls - frmMain.frm:
Code:
Option Explicit
Dim col As Collection
' // Asynchronous event from another threads
Public Function NewEvent(obj As prjSMT.Thread)
Dim n As Long
MsgBox "Calculation finished " & obj.ThreadID
' Remove from listbox
For n = 0 To lstThreads.ListCount - 1
If lstThreads.List(n) = obj.ThreadID Then lstThreads.RemoveItem (n): Exit For
Next
End Function
Private Sub cmdCreateThread_Click()
Dim param As ThreadData
Dim iid As UUID
Dim hThread As Long
Dim obj As IUnknown
Dim handler As clsEventHandler
Dim tid As Long
' Warning! This key should pass as copy. This example is incorrect.
param.key = InputBox("Input window name")
' Create event
param.hEvent = CreateEvent(ByVal 0&, 1, 0, 0)
' Create new thread
hThread = CreateThread(ByVal 0&, 0, AddressOf ThreadProc, ByVal VarPtr(param), 0, tid)
If hThread = 0 Then
MsgBox "Error creating thread", vbCritical
Exit Sub
End If
CloseHandle hThread
' Wait object initialization
WaitForSingleObject param.hEvent, INFINITE
' Remove event
CloseHandle param.hEvent
' If success
If param.IStream Then
IIDFromString StrPtr(IID_IUnknown), iid
' Get marshalled interface
CoGetInterfaceAndReleaseStream param.IStream, iid, obj
' Add to threads collections
Set handler = New clsEventHandler
Set handler.Producer = obj
Set handler.receiver = Me
col.Add handler, CStr(tid)
' Add to listbox
lstThreads.AddItem CStr(tid)
Else
MsgBox "Error creating object", vbCritical
End
End If
End Sub
' // Get current value from selected thread
Private Sub cmdGet_Click()
Dim obj As prjSMT.Thread
Dim key As String
If lstThreads.ListIndex < 0 Then Exit Sub
Set obj = col(lstThreads.List(lstThreads.ListIndex)).Producer
MsgBox obj.GetValue()
End Sub
Private Sub Form_Load()
' Patching runtime
RemoveLastDllError
Set col = New Collection
End Sub
And the helper class - clsEventHandler.cls, which allows you to handle the event object Thread:
Code:
' // Class for receiving and processing event from a prjSMT.Thread object
Option Explicit
Public receiver As frmMain
Dim WithEvents obj As prjSMT.Thread
Public Property Set Producer(newObj As prjSMT.Thread)
Set obj = newObj
End Property
Public Property Get Producer() As prjSMT.Thread
Set Producer = obj
End Property
Private Sub obj_ThreadFinished()
receiver.NewEvent obj
End Sub
Compile the both code as Native-code. Later, I'll do an example using only one project StandartEXE, ie no external dependencies.
www.youtube.com/watch?v=8TbdSiZRxm8
-
Re: Can ActiveX EXE be Reg-Free or run without Administrator rights?
-
1 Attachment(s)
Re: Can ActiveX EXE be Reg-Free or run without Administrator rights?
Use module modMultiThreading.bas as is. Just insert it into your project and do not think about how it works, take it as a given. Also, do not forget to add a reference type library.
Using the function vbCreateThread can create threads where the runtime is already initialized (what used to be impossible).
Thread function:
Code:
Public Type ThreadData
key As String
evt As Long
frm As frmThread
End Type
Public Sub ThreadProc(dat As ThreadData)
Dim frm As frmThread
' Create new instance of frmThread.frm
Set frm = New frmThread
' Set output parameter
Set dat.frm = frm
' Set caption
frm.Caption = dat.key
' Success
SetEvent dat.evt
' Show form
frm.Show vbModal
End Sub
Called by:
Code:
Private Sub cmdCreateThread_Click()
Dim param As ThreadData
Dim hThread As Long
Dim handler As clsEventHandler
Dim tid As Long
' Warning! This key should pass as copy. This example is incorrect.
param.key = InputBox("Input window name")
' Create event
param.evt = CreateEvent(ByVal 0&, 1, 0, 0)
' Create new thread
hThread = vbCreateThread(ByVal 0&, 0, AddressOf ThreadProc, ByVal VarPtr(param), 0, tid)
If hThread = 0 Then
MsgBox "Error creating thread", vbCritical
Exit Sub
End If
CloseHandle hThread
' Wait object initialization
WaitForSingleObject param.evt, -1
' Remove event
CloseHandle param.evt
End Sub
Bear in mind that in the example there is no synchronization. This can cause problems. Therefore, before using multithreading need to become familiar with it. To us falls into the hands of this wonderful tool as multithreading, but also on us great responsibility (such as in C ++). To many shared objects must be organized to synchronize access. You can use mutexes, critical sections, semaphores, etc. Also in this example, no marshaling, so each object lives in the thread in which it was created. Thus, events are generated in the other thread (as opposed to the 1st example). You can verify this by looking App.ThreadID value inside the event handler NewEvent.