从.NET(C++/CLI和C#)调用本机Win32代码

本文关键字:调用 本机 Win32 代码 NET C++ CLI | 更新日期: 2023-09-27 18:26:23

我正在为C#开发一个应用程序,我想使用DirectX(主要是Direct2D)作为它的图形组件。因此,我尝试使用C++/CLI作为本机C++代码和C#托管代码之间的中间层。到目前为止,我的解决方案中有3个项目:一个C#项目(我不会真正讨论它,因为它还没有给我带来任何问题),一个包含Windows.h的C++静态库,以及一个用于在其他两个项目之间封送信息的动态C++/CLI库。这是我到目前为止的代码:

在本机C++项目中,我有一个名为RenderWindowImpl的类,所以for只包含两个方法:

//RenderWindowImpl.h
#pragma once
#include <Windows.h>
class RenderWindowImpl final
{
public:
    RenderWindowImpl() = default;
    ~RenderWindowImpl() = default;
    int test();
private:
    static void InitializeWin32Class();
};

// RenderWindowImpl.cpp
#include "RenderWindowImpl.h"
int RenderWindowImpl::test()
{
    return 5;
}
void RenderWindowImpl::InitializeWin32Class()
{
    WNDCLASSEXW wc = { 0 };
    wc.cbSize = sizeof(WNDCLASSEXW);
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = nullptr;
    wc.hInstance = GetModuleHandleW(0);
    wc.hCursor = LoadCursorW(nullptr, IDC_ARROW);
    //wc.lpszClassName = L"wz.1RenderWindowImpl";
    //// TODO: error check
    //RegisterClassExW(&wc);
}

在我的C++/CLI项目中,我有一个名为RenderWindow的类,它充当RenderWindowImpl:的包装器

// wzRenderWindow.h
#pragma once
//#pragma managed(push, off)
#include "RenderWindowImpl.h"
//#pragma managed(pop)
using namespace System;
namespace wzRenderWindow {
    public ref class RenderWindow sealed
    {
    public:
        RenderWindow();
        ~RenderWindow();
        int test();
    private:
        RenderWindowImpl* impl;
    };
}

// wzRenderWindow.h.
#include "stdafx.h"
#include "wzRenderWindow.h"
wzRenderWindow::RenderWindow::RenderWindow()
{
    // Initialize unmanaged resource
    impl = new RenderWindowImpl();
    try
    {
        // Any factory logic can go here
    }
    catch (...)
    {
        // Catch any exception and avoid memory leak
        delete impl;
        throw;
    }
}
wzRenderWindow::RenderWindow::~RenderWindow()
{
    // Delete unmanaged resource
    delete impl;
}
int wzRenderWindow::RenderWindow::test()
{
    return impl->test();
}

当我编译我的项目时,我会收到以下警告和错误:

  1. 错误LNK1120 1未解析的externals wzRenderWindow d:''documents''visual studio 2015''Projects''WizEngCS''Debug''wzRendeerWindow.dll 1
  2. 警告LNK4075由于"/OPT:LBR"规范wzRenderWindow d:''documents''visual studio 2015''Projects''WizEngCS''wzRender Window''wzRenderWindowImpl.lib(RenderWindowImpl.obj)1而忽略"/EDITANDCONTINUE"
  3. 错误LNK2019未解析的外部符号__imp__LoadCursorW@8在函数"private:static void __cdecl RenderWindowImpl::InitializeWin32Class(void)"中引用(?InitializeWin32Class@RenderWindowImpl@@CAXXZ)wzRenderWindow d:''documents''visual studio 2015''Projects''WizEngCS''wzRender Window''wzRenderWindowImpl.lib(RenderWindowImpl.obj)1

这似乎是C++/CLI不喜欢的对LoadCursorW的调用,因为如果我注释掉那一行,代码会编译得很好。去掉Win32函数调用后,我能够成功地从C#应用程序调用RenderWindow::test(),输出预期的结果5。

我有点不知所措,因为我对C++/CLI的理解是,它非常善于包装本机C++类,以供托管.NET应用程序使用。我真的很想了解为什么我的代码没有编译。

作为一个相关的后续问题,我是不是找错树了?从.NET访问DirectX方法(或类似的基于COM的C/C++库)的常规方法是什么?我希望避免使用像SharpDX这样的第三方包装库。

从.NET(C++/CLI和C#)调用本机Win32代码

我通过将#pragma comment(lib, "User32.lib")放在RenderWindowImpl.cpp的顶部来解决问题。感谢@andlabs的修复。我不知道为什么这样解决了这个问题(在我以前的任何项目中,我从未需要显式链接到user32.lib)。