Проблема с интерфейсом C ++ VB6 - PullRequest
0 голосов
/ 02 апреля 2010

Я рву свои волосы, пытаясь решить эту проблему, любые идеи будут высоко оценены:

У меня есть C ++ exe, который получает данные с некоторого оборудования в основном потоке и обрабатывает их в другом потоке (поток 2).

Я использую c ++ dll для предоставления некоторых функций обработки данных, которые вызываются из потока 2.

У меня есть требование сделать еще один набор функций обработки данных в VB6. Таким образом, я создал VB6 DLL, используя надстройку vbAdvance для создать стандартную dll.

Когда я вызываю функции из этой библиотеки VB6 из основного потока, все работает именно так, как и ожидалось.

Когда я вызываю функции из этой библиотеки VB6 в потоке 2, я получаю нарушение прав доступа.

Я отследил ошибку до команды CopyMemory. Казалось бы, если это используется в вызове из основного потока, это нормально но при вызове из потока процесса это вызывает исключение. Почему это должно быть так? Насколько я понимаю, потоки используют одно и то же адресное пространство.

Вот код из моего VB dll

Public Sub UserFunInterface(ByVal in1ptr As Long, ByVal out1ptr As Long, ByRef nsamples As Long)
Dim myarray1() As Single
Dim myarray2() As Single
Dim i As Integer
ReDim myarray1(0 To nsamples - 1) As Single
ReDim myarray2(0 To nsamples - 1) As Single


With tsa1din(0)  ' defined as safearray1d in a global definitions module
    .cDims = 1
    .cbElements = 4
    .cElements = nsamples
    .pvData = in1ptr
End With

With tsa1dout
    .cDims = 1
    .cbElements = 4
    .cElements = nsamples
    .pvData = out1ptr
End With
CopyMemory ByVal VarPtrArray(myarray1), VarPtr(tsa1din(0)), 4
CopyMemory ByVal VarPtrArray(myarray2), VarPtr(tsa1dout), 4

For i = 0 To nsamples - 1
    myarray2(i) = myarray1(i) * 2
Next i
ZeroMemory ByVal VarPtrArray(myarray1), 4
ZeroMemory ByVal VarPtrArray(myarray2), 4


End Sub

UPDATE: -

Спасибо за все ваши комментарии, я действительно нашел решение, которое делает то, что мне нужно. Я поместил все манипуляции с указателями для массивов в отдельную функцию в dll VB. Я вызываю эту функцию из основного потока приложения C ++ во время процедуры установки. Затем поток обработки вызывает в dll другую подпрограмму, которая содержит только вычисления, которые должны быть выполнены с данными массива (и без команд CopyMemory). Это похоже на работу.

1 Ответ

1 голос
/ 02 апреля 2010

Вы должны инициализировать COM во втором потоке и инициализировать среду выполнения VB6 перед вызовом экспорта DLL VB6. Итак, сначала вызовите CoInitilize в рабочем потоке, затем создайте фиктивный объект из VB6 ActiveX DLL (и сразу же отпустите его), затем вызовите функцию.

Вы можете выполнить оба эти шага внутри своего экспорта, но это намного сложнее. Вы не можете ни вызывать встроенную функцию VB, ни объявлять функции API, только импортированные из библиотеки типов. Моя функция ввода темы запускается так:

'--- initialize COM libs
Call CoInitialize(0)
'--- create a VB6 object
Call CoCreateInstance(CLSIDFromProgID(PROGID_DUMMY), Nothing, CLSCTX_INPROC_SERVER, VBGUIDFromString(STR_IID_IUnknown), Nothing)
On Error GoTo ...

где все функции API взяты из библиотеки типов потоков. Вот функция, которая может сказать вам, если время выполнения VB на текущем потоке

Private Function pvIsVbRuntime() As Boolean
    Dim lIdx            As Long

    lIdx = GetModuleHandle("MSVBVM60.DLL")
    lIdx = GetProcAddress(lIdx, "__vbaSetSystemError")
    Call RtlMoveMemory(lIdx, ByVal lIdx + 9, 4)
    Call RtlMoveMemory(lIdx, ByVal lIdx, 4)
    If TlsGetValue(lIdx) <> 0 Then
        pvIsVbRuntime = True
    End If
End Function

Все функции API также импортированы из typelib. Он взломан, и я тестировал его только на SP6.

В любом случае, я думаю, что ваши проблемы должны быть хорошо задокументированы с помощью надстройки vbAdvance. Вам лучше "подготовить" рабочий поток в коде C ++.

...