Приведенное ниже решение создает библиотеки «YahooAPI.dll» и «YahooAPIWrapper.dll». (оригинальный проект найден здесь: http://pragmateek.com/using-c-from-native-c-with-the-help-of-ccli-v2/)
Из стороннего приложения я вызываю «YahooAPIWrapper.dll» со следующими результатами:
- функция «Foo» возвращает ожидаемые данные без проблем (не вызывает YahooAPI.dll).
- функция «GetRevision» через функцию «GetRevisionUtil», дважды вызывает «YahooAPI.dll»; каждый вызов показывает сообщение об ошибке без ошибок. Однако после показа второго сообщения появляется всплывающее окно: Внешнее исключение E0434352
Для устранения неполадок я добавил консольное приложение c ++.
Пожалуйста, смотрите комментарии в коде ниже.
YahooAPI.dll:
// YahooAPI.cs
using System;
using System.Windows.Forms;
public class YahooAPI
{
public string GetRevisionUtil(string rev)
{
MessageBox.Show("CurrentRev: " + rev);
return "rev_" + rev ;
}
}
Заголовок YahooAPIWrapper.dll:
// YahooAPIWrapper.h
#pragma once
#define DLL_EXP extern "C" __declspec(dllexport)
DLL_EXP void GetRevision(char* data_in, char *data_out);
DLL_EXP void Foo(char* data_in, char *data_out);
class YahooAPIWrapperPrivate;
class __declspec(dllexport) YahooAPIWrapper
{
private: YahooAPIWrapperPrivate* _private;
public:
YahooAPIWrapper();
~YahooAPIWrapper();
const char* GetRevisionFunc(const char* rev);
};
Пожалуйста, смотрите комментарии в функции: GetRevision
// YahooAPIWrapper.cpp
#include "stdafx.h"
#include <msclr\auto_gcroot.h>
#include <string>
#using "YahooAPI.dll"
#include <msclr\auto_gcroot.h>
#include "YahooAPIWrapper.h"
using namespace System::Runtime::InteropServices; // Marshal
DLL_EXP void GetRevision(char* data_in, char *data_out)
{
YahooAPIWrapper wrp;
const char* c = wrp.GetRevisionFunc(data_in); // 1st messagebox shows
const char* d = wrp.GetRevisionFunc(c); // 2nd messagebox shows
strcpy_s(data_out,100, d); // << HERE << 3rd party app throws 'external exception E0434352 '
// the console app throws the error 'Unhandled exception...'
}
const char* YahooAPIWrapper::GetRevisionFunc(const char* rev)
{
System::String^ managedCapi = _private->yahooAPI->GetRevisionUtil(gcnew System::String(rev));
return (const char*)Marshal::StringToHGlobalAnsi(managedCapi).ToPointer();
}
DLL_EXP void Foo(char* data_in, char *data_out)
{
int a_size = int(strlen(data_in));
std::string s_a = convertToString(data_in, a_size);
strcpy_s(data_out,100, s_a.c_str());
}
std::string convertToString(char* a, int size)
{
int i;
std::string s = "";
for (i = 0; i < size; i++) {
s = s + a[i];
}
return s;
}
class YahooAPIWrapperPrivate
{
public: msclr::auto_gcroot<YahooAPI^> yahooAPI;
};
YahooAPIWrapper::YahooAPIWrapper()
{
_private = new YahooAPIWrapperPrivate();
_private->yahooAPI = gcnew YahooAPI();
}
YahooAPIWrapper::~YahooAPIWrapper()
{
delete _private;
}
Консольное тестовое приложение:
// Test.cpp
#include <iostream>
#include <stdio.h>
#include "YahooAPIWrapper.h"
int main()
{
YahooAPIWrapper yahoo;
char* a = "aaaa";
char* b = "bbbb";
const char* c = yahoo.GetRevisionFunc(b); // messagebox shows
std::cout << c << std::endl;
GetRevision(a, b); // 1st & 2nd msgbox shows - then error: "unhandled exception..."
std::cout << a << std::endl;
std::cout << b << std::endl;
return 0;
}
РЕДАКТИРОВАТЬ: ошибка «консольного приложения» устранена. (Полный текст вышеуказанной ошибки: необработанное исключение 0x0f3c2fdd в Test.exe: 0xC0000005: Место записи нарушения прав доступа 0x00da7830.)
РЕДАКТИРОВАТЬ: вышеупомянутый проект был урезан следующим (см. Комментарии) - но по-прежнему отображается «Внешнее исключение E0434352»:
namespace Publics {
public class YahooAPI{
public static void GetRevisionUtil() {
string rev = "test";
MessageBox.Show("CurrentRev: " + rev);
//return "rev_" + rev;
}
}
}
// YahooAPIWrapper.h
#pragma once
#define DLL_EXP extern "C" __declspec(dllexport)
DLL_EXP void GetRevision(char* data_in, char *data_out);
DLL_EXP void Foo(char* data_in, char *data_out);
#include "stdafx.h"
#include <windows.h>
#include <msclr\auto_gcroot.h>
#include <string>
#using YahooAPI.dll"
#include "YahooAPIWrapper.h"
using namespace System::Runtime::InteropServices; // Marshal
DLL_EXP void GetRevision(char* data_in, char *data_out)
// this function builds & works fine with console
// however, immediately throws error (External Exception E0434352) when called by 3rd party app
// - does not even make it to MessageBox.
{
MessageBox(NULL, TEXT("msg1"), TEXT("Test"), MB_OK);
Publics::YahooAPI::GetRevisionUtil();
// Publics::YahooAPI^ obj = gcnew Publics::YahooAPI;
// obj->GetRevisionUtil();
strcpy(data_out, data_in);
}
РЕДАКТИРОВАТЬ: мои дальнейшие усилия по устранению этой ошибки помогли с помощью WinDbg - per: { ссылка }
Справка по фактическому использованию WinDbg была найдена здесь: https://netmatze.wordpress.com/2012/08/24/using-windbg-exe-and-sos-dll-to-debug-a-net-4-0-application/
Ниже приведен фрагмент из окна команд WinDbg.
Обратите внимание на использование из следующих команд:
.load C: \ Windows \ Microsoft.NET \ Framework \ v4.0.30319 \ sos.dll
! threads
ntdll!DbgBreakPoint:
772c2790 cc int 3
0:014> .load C:\Windows\Microsoft.NET\Framework\v4.0.30319\sos.dll
0:014> g
(9b3c.a350): C++ EH exception - code e06d7363 (first chance)
(9b3c.a350): C++ EH exception - code e06d7363 (first chance)
(9b3c.a350): C++ EH exception - code e06d7363 (first chance)
(9b3c.a350): CLR exception - code e0434352 (first chance)
(9b3c.a350): C++ EH exception - code e06d7363 (first chance)
(9b3c.87d8): Break instruction exception - code 80000003 (first chance)
eax=00353000 ebx=00000000 ecx=772fb3b0 edx=772fb3b0 esi=772fb3b0 edi=772fb3b0
eip=772c2790 esp=0e9eff44 ebp=0e9eff70 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
ntdll!DbgBreakPoint:
772c2790 cc int 3
0:014> !threads
ThreadCount: 2
UnstartedThread: 0
BackgroundThread: 2
PendingThread: 0
DeadThread: 0
Hosted Runtime: no
Lock
ID OSID ThreadOBJ State GC Mode GC Alloc Context Domain Count Apt Exception
0 1 a350 0299d1b8 20220 Preemptive 0BFC41D4:00000000 04f22fd8 0 STA System.IO.FileNotFoundException 0bfc2768
13 2 9b08 04f369c8 21220 Preemptive 00000000:00000000 04f22fd8 0 Ukn (Finalizer)
0:014> !PrintException /d 0bfc2768
Exception object: 0bfc2768
Exception type: System.IO.FileNotFoundException
Message: Could not load file or assembly 'YahooAPI.dll, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.
InnerException: <none>
Как вы можете видеть в приведенном выше окне, мне удалось разрешить исходную ошибку «Внешнее исключение E0434352» до «Исключение C ++ EH - код e06d7363». И, наконец, удалось разрешить эту ошибку для обыденного: «System.IO.FileNotFoundException». Мой YahooAPIWrapper.dll не смог найти мой (управляемый) YahooAPI.dll - даже если они были в одной и той же папке.
Строка дна: мое стороннее приложение имеет функцию конфигурации, позволяющую пользователю просматривать и выбирать папка для их Win32 dll.
Моя ошибка заключалась в том, что правильное расположение управляемой DLL (YahooAPI.dll) должно быть в той же папке, что и неуправляемая (YahooAPIWrapper.dll).
Ошибка была устранена простым копированием моей управляемой библиотеки DLL (YahooAPI.dll) в папку, в которой находится сторонний файл .Exe. Viola!