Click here to Skip to main content
13,898,580 members
Rate this:
Please Sign up or sign in to vote.
See more:
johnsontroye's article on UI Responsiveness got me most of the way through the problem of running a long method on a separate thread, but my application has several inputs and returned data that does not fit the example.

It seems as though the input data is correct, but the API call does not run correctly.

I am using a standard windows form instead of WPF, and I adapted the example to my application and got it running with the simulated LongRunningMethod, but I cannot get the argument passing correct (?) for my LongRunningMethod (API Call):

Private Function SomeLongRunningMethod((ByRef abData1() As Byte, _
                                       ByRef abData2() As Byte, _
                                       ByVal n As Integer, _
                                       ByRef abData3() As Byte) As String
     Dim someString as string = "1"
     abData1 = Method(abData1, abData2, n, abData3) 'API call
     Return SomeString
End Function

abData1() is a large byte array, and is the same as the Method return.

I would appreciate any help I can get with this, as I have struggled through many examples.

[Edited]Code is blocked in "pre" tags[/Edited]
Updated 30-Apr-11 9:24am
Rate this: bad
Please Sign up or sign in to vote.

Solution 1

By some reason, the suggested method is using System.Threading.ParameterizedThreadStart.

I never do this! You have to pass a System.Object argument, so run-time time would be of some container for all your parameters (struct, for example); and in the thread code you need to cast System.Object back to your structure, which is unsafe.

I never understood why doing such ugly things. There is a much better way. All you need is to pass "Me" reference. I wrap whole thread in some class and create a method the thread should be started with I call Body. I make it and instance (non-static) method, without parameters (important!). Using a regular constructor System.Threading.Thread(ThreadStart) allows to pass Body.

As Body is an instance method, all members of the wrapper class are passed through the invisible parameter "Me" of the type of the wrapper class; and this parameter is passed invisibly to Body. There is nothing unusual about it — this is how all instance methods work. But as a result, the method of the wrapper Body is started in a thread and all members of the instance of the member class are visible inside the method. So, you instantiate the wrapper class first. All parameters mentioned in your Question should be members of the wrapper. You need to initialize them before Thread.Start. For example, you can pass all those values in the wrapper's constructor.

I have a complete code sample, but it is in C#:
How to pass ref parameter to the thread[^].

Nevertheless it's quite easy to understand how it work using my explanation.

Good luck,
fjdiewornncalwe 4-May-11 14:36pm
Agreed. +5
Thank you, Marcus.
This answer was accepted and later rejected. What happened?
Menon Santosh 28-Mar-13 2:59am
Thank you, Menon.
Rate this: bad
Please Sign up or sign in to vote.

Solution 2

I implemented the solution suggested by SAKryukov and while it simplifies the passing of variables, the API call terminates instantly. I did a test of the variables passed to the thread by taking a hash of the three byte arrays and returning the results for comparison with the variables sent. This test verifies that data is correctly passed to the thread and that data can be returned. The API method runs correctly on the main thread.

Imports VB = Microsoft.VisualBasic
Imports CryptoSysAPI
Imports System.IO
Imports System
Imports System.Threading

Public Class ThreadWrapper

    Public Sub New(ByRef abData() As Byte, _
                                 ByRef abKey() As Byte, _
                                 ByVal n As Integer, _
                                 ByRef abInitV() As Byte)

        Initialize data passed to ThreadWrapper.
        ReDim abData1(0)
        ReDim abData2(0)
        ReDim abData3(0)

        abData1 = abData
        abData2 = abKey
        n1 = n
        abData3 = abInitV

        thread = New System.Threading.Thread(AddressOf Body)
    End Sub

    Public Sub start()
    End Sub

    Public Sub join()
    End Sub

    Public Sub Body()

        ' The API call.
        Me.abData1 = Blowfish.Encrypt(Me.abData1, Me.abData2, n1, Me.abData3)

    End Sub

    ' The definitions of the data passed to ThreadWrapper Class.
    Private abData1() As Byte
    Private abData2() As Byte
    Private n1 As Integer
    Private abData3() As Byte

    Public thread As System.Threading.Thread
End Class

' This is the call to the ThreadWrapper class to create a new thread and start the thread.
' All inputs are byte array except Mode.CBC which is an integer.

Public Class Protect

        Public Function Encyrpter(Inputs....) as Integer

                Dim tw As New ThreadWrapper(X_abData1, _
                                            X_abDerivedKeyHex, _
                                            Mode.CBC, _
                                            abInitVector, _

        End Function ' Encrypter.

End Class ' Protect.

fjdiewornncalwe 4-May-11 14:37pm
Then perhaps it would be a good idea for you to mark his answer as correct and +5 in recognition of his effort in answering your question so well.
NuttingCDEF 4-May-11 15:34pm
A few thoughts that might or might not be relevant. Note in particular that I'm much more familiar with C# than VB, so don't accept anything I've said about passing of arguments etc. as gospel without checking it.

1. In the New ThreadWrapper call, you specify 5 parameters - I assume that this is probably a legacy of various code edits, but if not, what effect does it have?

2. See - "Alternatively, with C#, you can just include the source code module CryptoSysAPI.cs in your project and there is no need to reference or use the class library DLL." - could you do this to be able to debug at least one layer further into the API - which might give you a clue as to what's going on.

3. ReDim abData1(0) etc. - what effect does the Redim actually have given that you assign to abData1 etc. almost immediately afterwards.

4. If Blowfish.Encrypt returns almost immediately, what does it return and what has it done to abData1 during the call (i.e. before the assignment of the return value to abData1) - maybe assign return value to a new abData4 and then abData1 = abData4?

5. Blowfish.Encrypt takes parameters ByVal (the VB default) as far as I can see - but arrays are reference types, so although you can't change the actual array that the caller's variable references, you can still change individual elements of the array. See and Your Sub takes arrays ByRef though it isn't clear to me why.

6. As it stands I don't see how your code extracts the cipher text produced by the encryption - is this just a result of giving code snippets or is there a real issue here? You assign a return value to abData1 - which previously referred to abData - but the assignment surely just means abData1 refers to the return value and not to abData - it doesn't mean the caller's abData refers to the return value. So unless Blowfish.Encrypt has actually modified the values in the abData1 argument (and hence values in abData) the result won't get passed out anywhere.
Thanks for VB.NET sample! My 5.
Thank you for this post again. I credited it in my recent solution:

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

  Print Answers RSS
Top Experts
Last 24hrsThis month

Advertise | Privacy | Cookies | Terms of Service
Web01 | 2.8.190306.1 | Last Updated 27 Mar 2013
Copyright © CodeProject, 1999-2019
All Rights Reserved.
Layout: fixed | fluid

CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100