C#中的非托管DLL无法正常工作

时间:2011-06-19 01:53:20

标签: c# .net c dll opencv

我一直在研究使用OpenCV进行一些跟踪的DLL。使用VS 2008(用于测试目的)在C控制台项目上工作。然后我创建了一个新的DLL项目并将其编译。我设置了所有内容,所以我只在Thread类上放了一个函数来调用单个函数。

然后我为GUI和其他东西创建了一个C#项目。 DLL加载正常(使用System.Runtime.InteropServices,方法启动(我可以看到OpenCV创建的捕获窗口),但跟踪没有完成。为了验证DLL实际工作,我加载了Python并调用了方法并且运行正常(正在跟踪)。

我刚开始使用托管代码上的非托管DLL。关于我做错了什么或者如何调试这个的任何想法?如果您还需要其他任何东西来帮助我解决这个问题,我会提供它。

提前致谢。

编辑:

我没有在DLL上使用类,我使用的是单个函数,Thread类来自C#上的System.Threading

我使用DLL的方式是这样的。

namespace GUI
{
    static class NativeTracking
    {
        [DllImport(@"__Tracking.dll")]
        public static extern void _Tracking();
    }
}

我把它放在像他的

这样的线程上
public GUI()
{
    InitializeComponent();
    _tracking = new Thread(_Tracking);
    _tracking.Start();
}

public _Tracking()
{
    while(True)
    {
        NativeTracking.Tracking();
    }
}

编辑:原生代码

原生代码,对于凌乱的格式感到抱歉。

标头文件

#include <cv.h>
#include <stdio.h>
#include <ctype.h>
#include <windows.h>
#include <highgui.h>
#include "..\original\project\myheader.h"
#include "..\original\project\myheader1.h"
#include "..\original\project\myheader2.h"
#include "..\original\project\myheader3.h"
#include "..\original\project\myheader4.h"
#ifdef __cplusplus
extern "C"{
#endif

    _declspec(dllexport) void Tracking();

#ifdef __cplusplus
}
#endif

实施

#include "exposed.h"

void Tracking( )
{
int flag = 1, i=0;
iplImgs imgs;
trackingTool tools;
helperTools helperTools;

CvCapture* capture = 0;
capture = cvCaptureFromCAM( 0 );

cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, 320);
cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, 240);
cvSetCaptureProperty(capture, CV_CAP_PROP_FPS, 20.0f);

imgs.image = 0;

    cvNamedWindow( "Window", 0 );
initHelperTools(&helperTools);
initTools(&imgs, &tools);

    for(;;){

    int c;
            IplImage* frame = 0;

    frame = cvQueryFrame( capture );        
    if( !frame )
        break;

    if( !imgs.image ){
            /* allocate all the buffers */
            prepareImages(&imgs, &tools, frame);
        }

        cvCopy( frame, imgs.image, 0 );
        cvCvtColor( imgs.image, imgs.grey, CV_BGR2GRAY );

        if( flag == 1 || conditionB ){
        someOperations(&imgs, &tools);
        if (conditionC)
            flag = 0;
        }
    else if( conditionD ){
        otherOps(&helperTools, imgs.grey);
        someTrack(&imgs, &tools, &helperTools, drawPoints);
        someCorrections(&tools);
        if ( condition ){
            if (!wasReset){
                wasReset = 0;
                continue;
            }
            if ( validation )
            someMoreOperations(&tools, corretions);
        }
    }   

    bufferHandlingOps(&imgs);


        c = cvWaitKey(10);
        if( (char)c == 27 )
            break;
    switch ((char)c){
        case 'p':
            drawPoints ^= 1;
            break;
        default:
            ;
    }
    }

    cvReleaseCapture( &capture );
    cvDestroyWindow("Window");
}

2 个答案:

答案 0 :(得分:3)

我看到的一个问题是您在本机代码中使用默认的C调用约定,即“__cdecl”,并且在P / Invoke“DLLImport”属性中,您要让它使用默认调用C#,即“__stdcall”。这可能会在您调用本机方法时抛出运行时异常。

此外,我意识到你没有传递任何参数或期望任何结果,但调用约定确实表示函数的装饰方式,这可能导致name mangling问题。 你可以:

  1. 将您的原生导出更改为“__declspec(dllexport)void __stdcall Tracking();”
  2. 或者更改DLLImport属性上的“CallingConvention”属性:[DllImport(@“__ Tracking.dll”)CallingConvention = CallingConvention = CallingConvention.Cdecl]

答案 1 :(得分:2)

DllImport(P / Invoke)的一个问题是不安全。您知道它只在运行时工作,因为如果出现以下情况,您无法在编译时检查它:

  • 方法的签名是正确的;
  • 方法的重整是正确的。

它非常受WIN32方法的欢迎,因为你会发现很多可行的例子,但对于你正在使用的lib,它是一个尝试和尝试直到它工作或你发现阻止你的特定问题的问题(记得验证dll在运行时是否在可执行文件的同一目录或系统目录中。)

我的建议是在C ++ / CLI中创建一个合适的包装器。它没有上面的问题,并且在出现问题时调试更为复杂。 Here是一个更复杂的例子,我在C语言中回调用C#公开。