> 普通の関数の時のように値を渡すことは可能でしょうか?
関数に値を渡すことは可能ですが、普通の関数のようにはいきません。
関数に渡せるのは32ビット値が一つだけです。
しかし、これだけでも工夫を凝らせば任意数の値を渡すことはできます。
以下に、解決策を示します。
ポインタ型は32ビット値ですので、CreateThread()を通して関数に渡すことができます。
ポインタを利用して関数に任意数の引数を渡すには、まず呼び出し側が引数リストを作成します。これには、malloc()関数を使うのがよいと思います。
引数リストですが、このリストには“引数へのポインタ”を格納すると、引数の型サイズを意識する必要がなくなります。
引数がByte型だろうがInteger型だろうが、構造体であってもポインタは常に32ビットだからです。
例えば、2個の引数を関数に渡したいとすれば、次のようになります。
呼び出し側のコード
コード:
Dim pParam As DWordPtr
pParam = malloc((2 + 1) * 4)
pParam[0] = 2 ' 0番目の要素には引数の数を格納すると、何かと便利です
pParam[1] = VarPtr(param1)
pParam[2] = VarPtr(param2)
Dim dummy As DWord ' スレッドのIDが格納される
hThread = CreateThread(ByVal NULL, 0, AddressOf(func), pParam, 0, VarPtr(dummy))
' 以下にコードの続きを記述します
新しいスレッド側のコード
例ではparam1がInteger型、param2がSTRUCT構造体だと仮定します(敢えて32ビット型を避けました)。
コード:
Function func(ByVal param As DWordPtr) As DWord
Dim tempI As *Integer
Dim p1 As Integer
Dim p2 As *STRUCT
tempI = param[1]
p1 = tempI[0] ' param1
p2 = param[2] ' param2(ポインタ参照)
' 以下にコードの続きを記述します
なお、pParamはいつかはfree()しなければなりません。
しかし、そのタイミングを間違えないようにしてください。
CreateThread()関数を呼び出した直後に解放してしまうと、新しく生成されたスレッド側で引数を正しく参照できなくなるかもしれません。
タイミングとしては、スレッドが終了する直前にスレッド側で解放するのが間違いがなくベストだと思いますが、その場合DLL化したときにどういった弊害が出るか僕には見当がつきません。
もしかしたら正常に動作するのかもしれませんが、インスタンスが異なるので正常に動作しない可能性があります。実際にテストしたわけではないので何とも言えません。
また、スレッドが終了したら呼び出し側で解放する方法もあります。
どちらにせよ、プログラム終了時に、解放し忘れたオブジェクトをWindowsが自動解放してくれるので、そちらに関してはあまり気を配る必要はないかもしれません。
極端な話、malloc()を何回も呼び出しておいて一回もfree()を使わなかったとしても、Windowsが解放してくれるから問題ないわけです。
大変お行儀の悪いプログラムですが、時折こういうのを見かけます。
> また、スレッド終了の際に戻り値を得たいのですが可能でしょうか?
関数の戻り値はスレッドの終了コードと見なされます。
これは、ExitThread()関数のパラメータに渡す値と同等のものです。
よって、関数の戻り値として使用できないといってよいでしょう。
こちらもポインタを介して値を返すなど工夫が必要です。
その場合、引数リストに戻り値用のポインタを準備しておき、そちらに戻り値を格納するのがよいと思います。ただし、free()する前に値を格納しましょう。