为什么我在C#项目中看不到一些C ++ DLL(支持CLR)?

时间:2012-06-04 12:46:54

标签: c# c++-cli

我编写了简单的C ++ Dll(win32),并将属性更改为“公共语言运行时支持(/ clr)” -

我创建了新的Simple winform项目(C#4.0),并创建了对C ++项目(C ++ DLL)的引用。

现在我在C#项目中看不到C ++ dll - 我无法使用它,我也不知道为什么。

2 个答案:

答案 0 :(得分:2)

您在C ++ dll中创建的类型仍然是原生的。您需要将它们显式声明为托管类型。例如:

ref class SomeType { }

声明托管类(请注意ref关键字)。虽然不是那么容易。您的本机代码不会神奇地转换为托管代码(一些基本数据类型,如int,但不是std::string)。如果您真的想充分利用C ++ / CLI进行互操作,那么您应该花时间了解语法差异。

答案 1 :(得分:2)

例如,如果您有这种非托管功能:

bool fooFunction(int firstParameter, int secondParameter);

如果要使托管代码可见,则必须将其包装(首先,简单,步骤)到托管类中:

public ref class MyClass abstract sealed
{
public:
    static bool Foo(int firstParameter, int secondParameter)
    {
        return fooFunction(firstParameter, secondParameter);
    }
};

这是一个简单的考试,如果你必须与复杂类型互操作,你可能需要将它们全部包装起来。例如,如果您必须与接受字符串的函数互操作,则必须对其进行管理。通常我会使用这样的类:

ref class UnmanagedString sealed
{
public:
    UnmanagedString(String^ content) : _content(content)
    { 
        _unicodePtr = _ansiPtr = IntPtr::Zero; 
    }

    ~UnmanagedString()
    { 
        Free(); 
    }

    operator LPWSTR()
    { 
        if (_content == nullptr)
            return NULL;

        Free();

        _unicodePtr = Marshal::StringToHGlobalUni(_content);
        return reinterpret_cast<LPWSTR>(_unicodePtr.ToPointer());
    }

    operator LPCSTR()
    { 
        if (_content == nullptr)
            return NULL;

        Free();

        _ansiPtr = Marshal::StringToHGlobalAnsi(_content);
        return reinterpret_cast<LPCSTR>(_ansiPtr.ToPointer());
    }

    virtual System::String^ ToString() override
    {
        return _content;
    }

    virtual int GetHashCode() override
    {
        return _content->GetHashCode();
    }

    virtual bool Equals(Object^ obj) override
    {
        return _content->Equals(obj);
    }

private:
    IntPtr _unicodePtr, _ansiPtr;
    String^ _content;

    void Free()
    {
        if (_unicodePtr != IntPtr::Zero)
        {
            Marshal::FreeHGlobal(_unicodePtr);
            _unicodePtr = IntPtr::Zero;
        }

        if (_ansiPtr != ntPtr::Zero)
        {
            Marshal::FreeHGlobal(_ansiPtr);
            _ansiPtr = IntPtr::Zero;
        }
    }
};

使用此类,您可以使用foo(LPCSTR pszText)调用void foo(UnamangedString(myManagedString))之类的函数。更复杂的是你必须做的调用以及你必须编写的更多代码才能在它们之间进行互操作。

注意:简单地将1:1托管接口暴露给非托管函数会使您的C#代码难以阅读,我建议您编写一个真正的OO接口来隐藏底层实现。