Экспорт функции С++, объявленной в vb6, с ошибкой выполнения удаленного вызова процедуры

У меня есть dll, написанная на С++, которая экспортируется так:

extern "C" {
    extern _declspec(dllexport) (VOID) Merge(LPCSTR szFileName, LPCSTR szMergeString, DWORD dwAlignment, BOOL fRepeat);
}

Эта функция определена в другом месте как:

extern _declspec(dllexport) (VOID) Merge(LPCSTR szFileName, LPCSTR szMergeString, DWORD dwAlignment, BOOL fRepeat)
{   
    Tools::Merge(gcnew String(szFileName), gcnew String(szMergeString), dwAlignment, fRepeat == TRUE);
}

В моей dll vb6 я объявил удаленный вызов следующим образом:

Private Declare Sub Merge Lib "Tools.dll" (fileName As String, mergeString As String, Alignment As Long, repeated As Boolean)

Затем я вызываю это в коде следующим образом:

Merge strPageFileName, "COPY", 5, True

Когда я запускаю приложение, я получаю «Ошибка автоматизации: сбой удаленного вызова процедуры» в окне сообщения.

Tools.dll находится в C:\Windows\system32. Я проверил с неверным именем dll, чтобы убедиться, что это не проблема, и получил сообщение об ошибке, говорящее о том, что файл не найден, поэтому я знаю, что это не так. Что-нибудь еще мне нужно сделать, чтобы заставить это работать?

EDIT: Изменение типа переменной в соответствии с ответом xxbbcc ниже позволило этому работать правильно. Однако это породило новую, до сих пор совершенно неразрешимую проблему. Я создал еще один вопрос здесь, в котором есть некоторые из подробности об этом.

Удаленный вызов происходит в dll COM+ внутри функции, которая возвращает тип integer в другую dll, отличную от COM. По какой-то странной причине функция COM+ dll теперь возвращает вариант типа VT_ERROR вместо целого числа. Я тщательно проверил это и определил, что не имеет значения, что я делаю с возвращаемым значением заранее, устанавливая для него любое значение и т. Д., Он всегда возвращает ошибку. Нечетная часть заключается в том, что значение ошибки, по-видимому, равно 0. Я вызвал CInt(returnValue), CStr(returnValue) и CLng(returnValue), и они возвращают 0, Error 0 и 0 соответственно.

Мне не удалось найти никакой информации, объясняющей, почему функция, которая должна возвращать целое число, вдруг вместо этого возвращает ошибку. Это дает мне ошибку несоответствия типа в функции, отличной от COM+, поскольку она пытается присвоить возврат локальному целому числу. Изменение этого на вариант позволило мне сделать указанные выше приведения. Вызов VarType(returnValue) дает 10, то есть vbError. Мы не хотим потенциально терять информацию об ошибках из других вызовов внутри dll COM+, поэтому я не могу просто игнорировать возвращаемое значение.


person Joe M    schedule 07.05.2013    source источник
comment
Пробовали ли вы запустить dumpbin /exports, чтобы убедиться, что ваша экспортированная функция называется именно так, как ее ищет ваш клиент VB6? (То есть, полностью ли имя функции не искажено в DLL?) Еще одна вещь, которую нужно проверить: действительно ли вызывается ваша функция C++? Если вы поставите в него точку останова, он сработает?   -  person xxbbcc    schedule 11.05.2013
comment
Да, он показывает функцию Merge, как и следовало ожидать. Проблема с отладкой заключается в том, что она находится на сервере, и нет удобного способа отлаживать ее или тестировать на моем ПК. Я попытался сделать это наоборот, с помощью regasm и запуская это как COM-dll, и таким образом выдается ошибка 438, указывающая, что он не может найти функцию.   -  person Joe M    schedule 11.05.2013
comment
Просто для проверки: вы использовали regasm или regsvr32? Если это простая C/C++ DLL, regasm ничего не сделает. Кроме того, вы не можете экспортировать простые функции в COM без библиотеки типов — у вас есть такая для вашей DLL? (Таким образом вы можете экспортировать глобальные функции в VB6, но тогда потребуется библиотека типов.)   -  person xxbbcc    schedule 11.05.2013
comment
Да, я немного поигрался с этим. Когда я запустил regasm, он создал библиотеку типов. В этом случае казалось, что он создает правильные записи реестра для класса enum, который просто имеет набор значений для выравнивания, но не создает запись для другого класса с функцией слияния. Я могу видеть значения выравнивания, представленные в vb6, но не функцию. Это не удается построить, когда я затемняю класс как объект, а затем устанавливаю его в класс инструментов.   -  person Joe M    schedule 13.05.2013
comment
В VB6 вы не можете видеть статические функции классов .NET - я не верю, что создатель библиотеки типов создает для этого запись модуля. Вы можете попробовать поискать Tools.Merge в VB6, но я сомневаюсь, что он там есть (никогда не пробовал). Для вашей глобальной функции Merge используйте файл DEF для ее экспорта, и тогда VB6 сможет ее вызвать. Вам все еще нужно исправить свое заявление Declare в соответствии с моим ответом. Прямо сейчас вы пытаетесь вызвать свою функцию с неправильными параметрами.   -  person xxbbcc    schedule 13.05.2013
comment
Нет, вы правы, его там нет.   -  person Joe M    schedule 14.05.2013
comment
Нам нужно больше подробностей о COM+ части системы. Как вызывается объект COM+? Как объявляется метод объекта COM+? Вероятно, вам следует опубликовать подробности в новом вопросе (и связать их, если хотите). Это звучит так, как будто вы вызываете метод, который работает успешно, но где-то неправильно интерпретируете вывод. Помните, как я сказал, что vbError значения, где scodes (HRESULTs) and that an scode could indicate error or success? A VbError of 0 is the scode/HRESULT called S_OK`, стандартный код COM для успешного завершения.   -  person Euro Micelli    schedule 17.05.2013


Ответы (3)


BOOL должен быть определен как Long в VB6, а переданное для него значение должно быть 0 или 1, а не логическими значениями. Это также должно быть ByVal - поскольку параметры передаются значениями в C / C++, вы должны убедиться, что ваша программа VB6 следует этому. Прямо сейчас ваша программа VB6 передает указатель на Boolean, а не на фактический Long. Ваши строки также должны быть определены как ByVal.

В этой статье содержится полезная информация о том, почему строки должны передаваться из VB6 как ByVal в код С.

Другое дело - я никогда не экспортировал функцию в VB6 с помощью declspec(dllexport). Раньше я много кодировал на C/VB6, но единственный способ, которым это когда-либо работало, — это файлы DEF. Я не могу объяснить, почему (может быть, из-за моего невежества). Игнорируйте эту часть моего ответа, если исправление параметра BOOL решает вашу проблему. :)

person xxbbcc    schedule 11.05.2013
comment
Похоже, это устранило проблему, так как файл теперь объединен правильно, но я получаю сообщение об ошибке несоответствия типа сразу после этого кода, что приводит к сбою и незавершению приложения, поэтому я пытаюсь это решить . Как только это распутается, я приму этот ответ. Спасибо! - person Joe M; 14.05.2013
comment
@JoeMajsterski спасибо, дайте мне знать, если у вас есть еще вопросы. Рад слышать, что ваша проблема исправлена. - person xxbbcc; 14.05.2013

Попробуйте объявить параметры String в своем заявлении VB6 Declare ByVal. Измените «имя файла как строку» на «имя файла ByVal как строку» и т. д.

person Mike Woolf    schedule 07.05.2013
comment
Неудачно. Спасибо за предложение. - person Joe M; 08.05.2013

Мое текущее решение этой проблемы состояло в том, чтобы написать крошечное консольное приложение на С++, которое вызывает экспортированную функцию и вызывает exe из dll vb6.

person Joe M    schedule 09.05.2013