2015-01-27 2 views
0

У меня есть следующий код C# (sample.dll).не удалось запустить неуправляемый тест модуля cpp для управляемого кода

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
namespace Sample 
{ 
    public class Worker 
    { 
    /// <summary> 
    /// Callback method signature to send array of values. 
    /// </summary> 
    /// <param name="values">The values.</param> 
    public delegate void FloatValuesReady(float[] values); 

    /// <summary> 
    /// Occurs when [float values are ready]. 
    /// </summary> 
    public event FloatValuesReady ReadFloatValues; 

    /// <summary> 
    /// Sums the specified i. 
    /// </summary> 
    /// <param name="i">The i.</param> 
    /// <param name="j">The j.</param> 
    /// <returns></returns> 
    public int Sum(int i, int j) 
    { 
    return i + j; 
    } 

    /// <summary> 
    /// Gets the Student object. 
    /// </summary> 
    /// <returns></returns> 
    public ManagedStudent GetStudent() 
    { 
    Console.WriteLine("Enter a Name:"); 
    string text = Console.ReadLine(); 
    if (text != string.Empty) 
    { 
     return new ManagedStudent { Name = text }; 
    } 
    return new ManagedStudent { Name = "NoName" }; 
    } 

    /// <summary> 
    /// Read some float values from Console and give it back to the caller using ReadFloatValues callback. 
    /// So Caller should add event handler to ReadFloatValues event. 
    /// </summary> 
    public void GetSomeFloatValues() 
    { 
    List<float> values = new List<float>(); 
    Console.WriteLine("Enter 4 valid float values for the Native App"); 
    while (values.Count < 4) 
    { 
     string valueText = Console.ReadLine(); 
     float value; 
     if(float.TryParse(valueText, out value)) 
     { 
      values.Add(value); 
     } 
    } 
    if (this.ReadFloatValues != null) 
    { 
     this.ReadFloatValues(values.ToArray()); 
    } 
    } 
    } 
    /// <summary> 
    /// A Managed Class 
    /// </summary> 
public class ManagedStudent 
{ 
    public string Name { get; set; } 
} 
} 

Я создал C++ обертки для вышеприведенного sample.dll для Асесса управляемого кода в неуправляемом коде (wrapper.dll). Ниже приведен код для SampleWrapper.h, SampleWrapper.cpp, NativeInterface.h.

/*Sample Wrapper.h*/ 
using namespace System; 
using namespace Sample; 
namespace Wrapper 
{ 
    public ref class SampleWrapper 
    { 
    /* Private Constructor to achieve signle ton*/ 
    SampleWrapper(void) 
    { 
     workerObj = gcnew Worker(); 
    workerObj->ReadFloatValues += gcnew Worker::FloatValuesReady(this, &Wrapper::SampleWrapper::FloatArrayReadyMethod); 
    } 
public: 
    Worker^workerObj; 
    /* Static reference to single ton instace. 
    In order to use applications built in C.*/ 
    static SampleWrapper^Instance = gcnew SampleWrapper(); 
    void FloatArrayReadyMethod(array<float>^values); 
    }; 
    } 


    /*NativeInterface.cpp/* 
#ifdef __cplusplus 
extern "C" 
{ 
    #endif 
/* Un managed type definition of student equalent to the Managed*/ 
typedef struct 
{ 
    char* name; 
}UnManagedStudent; 

    /* A simple interface using the premitive types. Accepts 2 paramters  and retun*/ 
    __declspec(dllexport) int SumFromCSharp(int i, int j); 

    /* An interface to get the Student Information in a Structure. 
    This function calls the C# class method and gets the managed Student Object 
    and converts to unmanged student*/ 
__declspec(dllexport) UnManagedStudent GetStudent(); 

    /* Function pointer to a native function to achieve call back*/ 
    typedef void (*GetFloatArrayCallback) (float values[], int length); 

    /* An interface that makes call to C# to read some float values. 
    The C# worker respond back in event call back. 
    In order to pass the information back to the native app 
    it should give the callback pointer*/ 
    __declspec(dllexport) void GetFloatArrayFromCSharp(GetFloatArrayCallback cb); 

    #ifdef __cplusplus 
     } 
     #endif 

/*sampleWrapper.cpp*/ 

#include "SampleWrapper.h" 
#include "NativeInterface.h" 
using namespace Sample; 

    namespace Wrapper 
    { 
    #ifdef __cplusplus 
    extern "C" 
    { 
    #endif 
    void copyManagedStringToCharPointer(char target[], System::String^inputString) 
    { 
    int maxSize = inputString->Length; 
    if (maxSize > 0) 
    { 
    for (int index = 0; index < maxSize; ++index) 
    { 
     target[index] = (char)inputString->default[index]; 
    } 
    target[maxSize] = '\0'; 
    } 
    } 

    void copyManagedFloatToUnfloatArray(float target[], array<float>^values) 
    { 
    int maxSize = values->Length; 
    if (maxSize > 0) 
    { 
    for (int index = 0; index < maxSize; index++) 
    { 
     target[index] = (float)values[index]; 
    } 
    } 
    } 

__declspec(dllexport) int SumFromCSharp(int i, int j) 
    { 
    Worker^worker = SampleWrapper::Instance->workerObj; 
    return worker->Sum(i,j); 
    } 

    __declspec(dllexport) UnManagedStudent GetStudent() 
    { 
    Worker^worker = SampleWrapper::Instance->workerObj; 
    ManagedStudent^studentObj = worker->GetStudent(); 
    String^mName = studentObj->Name; 
    UnManagedStudent studentStruct; 
    studentStruct.name = new char[mName->Length]; 
    copyManagedStringToCharPointer(studentStruct.name,mName); 
    return studentStruct; 
    } 

    GetFloatArrayCallback floatArrayCallback; 
    __declspec(dllexport) void GetFloatArrayFromCSharp(GetFloatArrayCallback cb) 
    { 
    floatArrayCallback = cb; 
    Worker^worker = SampleWrapper::Instance->workerObj; 
    worker->GetSomeFloatValues(); 
    } 

    void SampleWrapper::FloatArrayReadyMethod(array<float>^values) 
    { 
    float *nativeValues = new float[values->Length]; 
    copyManagedFloatToUnfloatArray(nativeValues, values); 
    floatArrayCallback(nativeValues, values->Length); 
    } 

    #ifdef __cplusplus 
    } 
#endif 
    } 
#include "DemoNativeDll.h" 
    #include "NativeInterface.h" 

using namespace nsNativeDll; 

CDemoNativeDll::CDemoNativeDll(void) 

{ }

CDemoNativeDll::~CDemoNativeDll(void) 
    { 
    } 

    int CDemoNativeDll::GetSum(int value1, int value2) 
    { 
    return SumFromCSharp(value1,value2); 
    } 

Затем я создал блок случае Native.dll ниже

#include "stdafx.h" 
#include "CppUnitTest.h" 
#include "..\NativeDll\DemoNativeDll.h" 
#include "..\Wrapper\NativeInterface.h" 

using namespace Microsoft::VisualStudio::CppUnitTestFramework; 
using namespace nsNativeDll; 

namespace UnitTest1 
{  
    TEST_CLASS(UnitTest1) 
    { 
    public: 

    TEST_METHOD(TestMethod1) 
    { 
     CDemoNativeDll* obj = new CDemoNativeDll(); 
     int sum = obj->GetSum(10,15); 

     Assert::AreEqual(sum,15); 
     // TODO: Your test code here 
    } 

    }; 
    } 

Я получаю исключение EEFileLoadException. Как перенаправить это исключение. Я использую Visual Studio 2012 cppunit.

ответ

1
__declspec(dllexport) void GetFloatArrayFromCSharp(GetFloatArrayCallback cb); 

Использование __declspec (dllexport) - это простой способ выдать управляемый код на нативный код. Но это слишком просто, нет разумного способа обнаружить какие-либо ошибки в управляемом коде. Который любит бросать исключения, когда что-то идет не так. Все, что вы можете видеть, это исключение «это не работает», без каких-либо способов узнать что-либо об управляемом исключении. Отсутствие сообщения об исключении, отсутствие доступа к трассировке стека.

Вы получаете предварительный просмотр того, насколько сложно будет поддерживать вашего клиента. Кто позвонит вам и скажет, что «это не сработало». Ничто не может помочь, если вы не можете запустить отладчик на своем компьютере. Это, как правило, трудно найти.

Ну, у вас есть один на вашем, вы можете, по крайней мере, использовать его для диагностики отказа блока. Project + Properties, Debugging, измените параметр «Тип отладчика» с «Авто» на «Смешанный». Это позволяет использовать управляемый механизм отладки, теперь вы можете посмотреть сведения об исключении. Обычно стандартное болото, «Файл не найден», является очень распространенным случаем. Тем более, что CLR не имеет веских оснований искать управляемую сборку в каталоге, где она хранится прямо сейчас, настройка основного приложения-домена - это то, что вы не можете сделать. Вам, вероятно, придется поместить его в GAC или переместить бегун для тестирования cppunit, чтобы он находился в том же каталоге, что и ваши DLL. Fuslogvw.exe - хорошая утилита для диагностики проблем разрешения сборки, она показывает, где CLR ищет сборку и какую конфигурацию она использует.

Но не стесняйтесь, чтобы этот результат теста устройства попал в категорию «серьезных сбоев». Рассмотрите возможность продвижения COM-взаимодействия или хоста CLR, они оба дают вам код ошибки HRESULT и поддерживают IErrorInfo для получения сообщения об исключении.

Смежные вопросы