Jump to content
  • Advertisement
Sign in to follow this  
arjansingh00

DX11 DirectX C++ DLL for C# Problem?

This topic is 712 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I am currently trying to use my DirectX C++ engine in a C# project to develop a level editor. Based on the advice I was given I have decided to write my engine in a DLL and use p/invoke in C#. http://gamedev.stackexchange.com/questions/124249/how-do-i-render-my-directx-c-engine-to-a-c-panel

An unhandled exception of type 'System.BadImageFormatException' occurred in DirectXinForms.exe

I don't know what the problem is but can someone help me fix this? Maybe there's an issue with the DLL aswell. Here is my code for the C++ DLL & C# Windows Forms project. I am also unable to directly add a reference to the DLL in C# but using 

[DLLImport]

 seemed to work. 

 

DLL Header.h

 

#pragma once


#define DllExport __declspec(dllexport)


#include <windows.h>
#include <windowsx.h>
#include <d3d11.h>
#include <d3dx11.h>
#include <d3dx10.h>
#include <DirectXMath.h>


using namespace DirectX;


// include the Direct3D Library file
#pragma comment (lib, "d3d11.lib")
#pragma comment (lib, "d3dx11.lib")
#pragma comment (lib, "d3dx10.lib")


// global declarations
IDXGISwapChain *swapchain;             // the pointer to the swap chain interface
ID3D11Device *dev;                     // the pointer to our Direct3D device interface
ID3D11DeviceContext *devcon;           // the pointer to our Direct3D device context
ID3D11RenderTargetView *backbuffer;    // the pointer to our back buffer


extern "C"
{
__declspec(dllexport) void InitD3D(HWND hWnd, int Width, int Height);    // sets up and initializes Direct3D
}


extern "C"
{
__declspec(dllexport) void RenderFrame(void);     // renders a single frame
}


extern "C"
{
__declspec(dllexport) void CleanD3D(void);        // closes Direct3D and releases memory
}

DLL Main.cpp

 

#include "Header.h"


void InitD3D(HWND hWnd, int Width, int Height)
{
// create a struct to hold information about the swap chain
DXGI_SWAP_CHAIN_DESC scd;


// clear out the struct for use
ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC));


HRESULT hr = S_OK;


// fill the swap chain description struct
scd.BufferCount = 2;                                    // one back buffer
scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;     // use 32-bit color
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;      // how swap chain is to be used
scd.OutputWindow = hWnd;                                // the window to be used
scd.SampleDesc.Count = 8;                               // how many multisamples
scd.SampleDesc.Quality = 1;
scd.Windowed = TRUE;
scd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;     // allow full-screen switching// windowed/full-screen mode
// create a device, device context and swap chain using the information in the scd struct


hr = D3D11CreateDeviceAndSwapChain(NULL,
D3D_DRIVER_TYPE_HARDWARE,
NULL,
NULL,
NULL,
NULL,
D3D11_SDK_VERSION,
&scd,
&swapchain,
&dev,
NULL,
&devcon);


// get the address of the back buffer
ID3D11Texture2D *pBackBuffer;
swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);


// use the back buffer address to create the render target
dev->CreateRenderTargetView(pBackBuffer, NULL, &backbuffer);
pBackBuffer->Release();


// set the render target as the back buffer
devcon->OMSetRenderTargets(1, &backbuffer, NULL);


// Set the viewport
D3D11_VIEWPORT viewport;
ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT));


viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
viewport.Width = Width;
viewport.Height = Width;


devcon->RSSetViewports(1, &viewport);


}


void RenderFrame(void)
{
// clear the back buffer to a deep blue
devcon->ClearRenderTargetView(backbuffer, D3DXCOLOR(0.0f, 0.2f, 0.4f, 1.0f));


// do 3D rendering on the back buffer here


// switch the back buffer and the front buffer
swapchain->Present(0, 0);
}


void CleanD3D(void)
{
// close and release all existing COM objects
swapchain->Release();
backbuffer->Release();
dev->Release();
devcon->Release();
}

C# Project:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;


namespace DirectXinForms
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }


        private void button1_Click(object sender, EventArgs e)
        {
            Dengine.Initialize(panel1.Handle, panel1.Width, panel1.Height);
            Dengine.RenderFrame();
        }


        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            Dengine.CleanD3D();
        }
    }


    public class Dengine
    {
        [DllImport("DirectXENGINEDLL.dll")]
        public static extern void Initialize(IntPtr window, int Width, int Height);


        [DllImport("DirectXENGINEDLL.dll")]
        public static extern void RenderFrame();


        [DllImport("DirectXENGINEDLL.dll")]
        public static extern void CleanD3D();
    }


}
Edited by arjansingh00

Share this post


Link to post
Share on other sites
Advertisement

BadImageFormatException tends to mean you are trying to load a 32-bit dll from a 64-bit process or the other way around, so start by making sure you are not doing that. For example, using Any CPU in your C# project means your process might be 32-bits, it might be 64 bits. If you need to use Any Cpu, you'll need to compile your native dll for both 32 and 64 bits, then use the one that makes sense at runtime.

Share this post


Link to post
Share on other sites

Funnily enough communication between C# and C++ is something I was just looking in to this morning. 

 

As an alternative to p/invoke have you considered using managed c++? If you compile your C++ project with /clr and link it as a reference to you C# project it makes the whole process much cleaner.

 

On the C++ side of things you can have a singleton interface to your engine:

namespace CPlusPlusLib
{
 public ref class SomeCPlusPlusInterface
 {
   ...

   static property SomeCPlusPlusInterface^ Instance
   {
     SomeCPlusPlusInterface^ get()
     {
       if( ourInstance == nullptr )
       {
         ourInstance = gcnew SomeCPlusPlusInterface();
       }

       return ourInstance;
     }
   }

   ...

   String^ GetString()
   {
     return "Hello from C++";
   }

   ...

   static SomeCPlusPlusInterface^ ourInstance = nullptr;
 }
}

Then in C#:

using CPlusPlusLib;

...

private void SomeFunction()
{
 String cPlusPlusString = SomeCPlusPlusInterface.Instance.GetString();

 ...
}

Not sure about the overhead that you incur by using managed c++, but I really like that you don't have to explicitly declare everything from the DLL that you want to use.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!