Експортиране на c++ функция, декларирана във vb6, получаване на неуспешно извикване на отдалечена процедура грешка по време на изпълнение

Имам dll, написан на C++, който се експортира така:

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);
}

В моя vb6 dll декларирах дистанционното повикване по следния начин:

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, за да се уверя, че не е това проблемът, и получих грешка, че не може да намери файла, така че знам, че не е това. Нещо друго, което трябва да направя, за да заработи?

РЕДАКТИРАНЕ: Промяната на типа променлива според отговора на xxbbcc по-долу позволи това да функционира правилно. Това обаче създаде нов, засега напълно неразрешим проблем. Създадох друг въпрос тук, който има някои от подробности за него.

Отдалеченото повикване се извършва в COM+ dll, вътре във функция, която връща тип integer към друга не-COM dll. По някаква странна причина функцията на 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 към C код.

Друго нещо - никога не съм експортирал успешно функция към 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

Опитайте да декларирате параметрите на низа във вашия оператор VB6 Declare ByVal. Променете „име на файл като низ“ на „ByVal име на файл като низ“ и т.н.

person Mike Woolf    schedule 07.05.2013
comment
Без късмет. Благодаря все пак за предложението. - person Joe M; 08.05.2013

Текущото ми решение за това е да напиша малко конзолно приложение на c++, което извиква експортираната функция и извиква exe от vb6 dll.

person Joe M    schedule 09.05.2013