13

I am writing a GUI tool in C# to parse and display the data output of another program written in C. In order to parse the data I need to know the data structures which are specified in a number of C header files. Thus I need to incorporate those C header files into my C# project. My questions are:

1) After some research I came to conclude that the best way is to create a new C++/CLI project in my solution, import the C header files into this new project, write some C++/CLI classes that act as thin wrappers for the data structures defined in the C header files, then reference the C++/CLI wrapper classes from the C# code. Is this the best approach, or is there a better way?

2) I ran into a reference problem. Here's my simplified code to illustrate the problem:

Original C header in C++/CLI project

#define ABC  0x12345

Wrapper class in C++/CLI project

#include "my_c_header.h"

namespace C_Wrappers {
    public ref class MyWrapper {
        public:
            property unsigned int C_ABC {
                unsigned int get() { return ABC; }
            }
    }
 }

User class in C# project

using C_Wrappers;
using System;

namespace DataViewer {
    public partial class MainForm : Form {
        private  MyWrapper myWrapper = new MyWrapper();
        public MainForm() {
            Console.WriteLine(myWrapper.C_ABC.ToString());
        }
    }
 }

In the C# project I added a reference to the C++/CLI project (using right click > Add Reference). During build I got an error in the C# project: "The type or namespace 'C_Wrappers' could not be found (are you missing a using directive or an assembly reference?)."

I thought I did everything I was supposed to. What should I do to fix this error?

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
Thomas Nguyen
  • 464
  • 1
  • 5
  • 16
  • 1
    Did you make sure the C++/CLI project compiled first (as in compiled before the C# project)? If the C# compiles first and the dll wasn't produced for the CLI project, it'll say that. – Will Custode Oct 03 '13 at 16:04
  • Is the C++/CLI namespace inside another namespace? Use Object Browser to have a look-see. – Hans Passant Oct 03 '13 at 16:05
  • have you also put a "project dependency" between those 2 project.... – alexbuisson Oct 03 '13 at 16:07
  • @HansPassant There's only one namespace in C++/CLI project and it is as shown. – Thomas Nguyen Oct 03 '13 at 16:24
  • @alexbuisson - I checked and the C# project is dependent on the C++/CLI project – Thomas Nguyen Oct 03 '13 at 16:27
  • @WilliamCustode - The C++/CLI project is built first. I verified that the C++/CLI project was built successfully and the DLL is present in the Debug folder. – Thomas Nguyen Oct 03 '13 at 16:28
  • @ThomasNguyen: if this is a C interface you could use directly **P/Invoke**, map the structures and create a C# wrapper around the **DllImports**. A C++/CLI wrapper is really useful when you have an object-oriented API or want to simulate one. – Pragmateek Oct 03 '13 at 18:05
  • http://xmight.blogspot.com/2013/04/cli-bridge-to-connect-c-project-to-csharp.html – Buddhika Chaturanga Feb 09 '18 at 14:17

2 Answers2

24

In my own solution, I had 4 projects:

  1. the C++ project and the test code
  2. the C++ DLL project which only compiles a DLL out of the first project source using dynamic links
  3. the wrapper project which is only an adapter using C++/CLI, which wraps around the raw C++
  4. the C# WPF project which was my graphical interface.

Here's my translation of the provided link above.

The C++ DLL project

Make your C++ code into a DLL lib.

  1. Inside Visual Studio, go to File > New > Project, Select Win32 project from the Visual C++ tab.
  2. Choose a name for both the project and the Solution, the solution will have all the projects inside.
  3. Inside the assistant for Win32 Application, click next, check the DLL box, then Empty project then click Finish.

Project creation Project assistant

Code to add

This is my C++ header for the dll (minus lot of stuff).

Token.h

#pragma once
#define DLLEXP   __declspec( dllexport )

DLLEXP void pop_back(std::string& str);

DLLEXP std::string testReturnString();

DLLEXP int getRandomNumber();

There's nothing to change inside the CPP.

Build the project, you should have a DLL and a LIB file to include in the C# project debug dir.

The C++/CLI wrapper

This project serves as an interface between the native code from the previous project, and managed code of the GUI.

  1. Add a new project (class library in Visual C++) (called "Wrapper" in this example) to the solution
  2. Add the path to the native project with the additional Include directories
  3. Add the native project as a reference for the new project (right click > References... > Add New Link)
  4. In Properties > Linker > Input, put the name of the native dll in the delayed loading of DLLs (Computations.dll in this example) field

The C++/CLI code

My wrapper is only a class which looks something like this (minus my own code).

Wrapper.h

#include "Token.h" // include your C++ header

#include <string>
#include <iostream>

namespace Wrapper {

    // noticed the ref?
    public ref class TokenAnalyzer
    {

    public:
        TokenAnalyzer(){
        };

        void Init();
            // use the C++/CLI type, like String^ (handles)
        System::String^ ProcessLine(int lineNbr, System::String^ line);
    };
}

Nothing special inside the CPP except that you have to include #include "stdafx.h".

It should also builds into a DLL which you will include inside the C# debug dir.

Just a useful function I found somewhere on SO but don't remember where that you might need. It convert C++/CLI String handle into a C++ standard string.

std::string MarshalString (String ^ s) {
        using namespace Runtime::InteropServices;
        const char* chars = 
            (const char*)(Marshal::StringToHGlobalAnsi(s)).ToPointer();
        std::string os = chars;
        Marshal::FreeHGlobal(IntPtr((void*)chars));
        return os;
    }

The C# project

Add to the solution a new project (C # Windows Form or WPF or whatever you want!) and set it as the startup project (right-click > set as startup project).

  1. Add the C++/CLI project as a reference for the new project
  2. Add Directive using Wrapper; in source code form

Use it like:

/// Store the C++/CLI Wrapper object.</summary>
private Wrapper.TokenAnalyzer mTokenAnalyzer = new TokenAnalyzer();

Update 2016/05/06

Ashwin took the time to make a sample project and a blog post tutorial which may help further.

Emile Bergeron
  • 17,074
  • 5
  • 83
  • 129
  • For some reason my company is blocking your link :( – Thomas Nguyen Oct 03 '13 at 16:29
  • I'm writing a little tutorial inside my answer, won't be long! – Emile Bergeron Oct 03 '13 at 16:31
  • Voilà! This should get you started I hope. – Emile Bergeron Oct 03 '13 at 17:00
  • Wow, thanks for the taking the time to write so much. But unfortunately it doesn't help me much. First I don't need to do a native DLL project as I don't have native code other than a bunch of C headers which I can put directly into the C++/CLI project. Second a reference from C# project to C++/CLI project was created and the dependency is correct (C++/CLI project built before C# project) and the C++/CLI DLL was created successfully, yet the C# code cannot reference any class in C++/CLI (the error says the namespace inside C++/CLI doesn't exist or couldn't be found). How to fix this? – Thomas Nguyen Oct 03 '13 at 17:06
  • Have you put the Dll outputted by the C++/CLI project beside the C# EXE inside the C# project Debug folder? I made myself a post-build event inside the C++/CLI DLL project to copy the outputted DLL automatically into the C# project's debug directory. – Emile Bergeron Oct 03 '13 at 17:41
  • I built the C++/CLI project, then manually copy the DLL from that project to the Debug directory of the C# project, then rebuilt the C# project. But the error still persists. Very frustrating! Any other way to force the C# project to see the C++/CLI DLL? – Thomas Nguyen Oct 03 '13 at 21:39
  • Maybe clean and rebuild? When messing around my own project to test yesterday, I got the same problem as you, I cleaned and rebuild and it worked! – Emile Bergeron Oct 04 '13 at 15:10
6

For me, the answer to this similar question solved that same error in C#.

(i.e. I had a wrapper header file in my C++\CLI project, but forgot to include a .cpp file as well (even though it only has two lines in it: #include "stdafx.h" and #include "Wrapper.h"))

Community
  • 1
  • 1
Bartel
  • 198
  • 1
  • 7