Using a c++ dll in c#
How can I go about trying to send image via c++ to display on c#
I'm trying to do so asynchronously, every time a new image is acquired by the c++ dll I'll send it to the winform to display.
If more code is needed to explain this more than willing to share 🙂 just know I haven't wrote anything in c# yet just the dll
56 Replies
you would likely use use P/Invoke https://learn.microsoft.com/en-us/dotnet/standard/native-interop/pinvoke
Platform Invoke (P/Invoke) - .NET
Learn how to call native functions via P/Invoke in .NET.
you would need to expose a C API from your C++ library
then, you can use P/Invoke to call those C API functions from C#
you cannot call C++ from C# directly, you need the C API wrappers that only use things like
struct
s and pointers and so onThere's a useful source generator, too, that will generate the bunk of the binding code for you
https://github.com/microsoft/CsWin32 found it, I think this is the one
that is only for Win32 APIs, it does not help for a custom DLL
Ah, whoops, wrong generator then. Lemme search some more
Ah, it's built-in...?
https://learn.microsoft.com/en-us/dotnet/standard/native-interop/pinvoke-source-generation
okay so how would i set up c in a way that it can use it? do i put the image in a struct and create a c event?
sorry if the question is dumb but i'm new to programming
If you're new to programming, and apparently, you're making both the C++ part and the C# part...
...why even compilcate things instead of doing everything in one language?
to aquire the images i'm using an sdk, can i use the libraries in c#?
can you show what the functions in the SDK look like
Well, depends, what libraries?
what do you want to know about the library? not sure what you mean
dlls, libs and header files
What does it do, why do you need it
it acquires the image
Wgat image, where from?
virtual void image_acquired(
uint16_t bank, // Internal image ID, device DDR bank number.
uint16_t frame, // Internal image ID, device DDR frame number.
int width, // Image width, pixels.
int height, // Image height, pixels.
const uint16_t* image, // Image, points to widthheight array of uint16_t elements.
bool more_available) override // true - another image is available.
{
UNREFERENCED_PARAMETER(bank);
UNREFERENCED_PARAMETER(frame);
sync_print("image acquired: ", image_index, " ", width, "", height);
++image_index;
if (more_available)
{
sync_print("more_available = true, it seems that our program is too slow");
return;
}
// Save one image to current directory - just as example.
// Note: in real program is is better to make this asynchronously, by copying an image
// to your own storage. Save operation should be executed asynchronously in another thread.
// Correct image_acquired implementation should contain only one copy memory call.
//
// In this example, for symplicity, we save one image synchronously.
if (image_index == 16) // just any image index
{
const char* file_name = "stn_image.raw";
std::string save_result = utilities::save_file(file_name, reinterpret_cast<const uint8_t>(image),
widthheightsizeof(uint16_t));
if (save_result.empty())
{
sync_print(FUNCTION, " Image is saved: ", file_name);
}
else
{
sync_print(FUNCTION, " Error saving image to file ", file_name, ". ", save_result);
}
}
every time an image is acquired it calls image_acquired
i used to just save the image like this
std::string utilities::save_file(
const char file_name, // [in] file name
const uint8_t* data, // [in] data to save
int size) // [in] data size (bytes)
{
FILE* f = std::fopen(file_name, "wb");
if (f == nullptr)
{
std::ostringstream s;
s << "Cannot open file " << file_name << ". " << strerror(errno);
return s.str();
}
std::string result;
size_t write_result = std::fwrite(data, sizeof(uint8_t),size, f);
if (write_result < static_cast<size_t>(size))
{
std::ostringstream s;
s << "fwrite failed. write_result " << write_result << " expected " << size <<
" file name " << file_name;
result = s.str();
}
fclose(f);
return result;
}
now i'm trying to send it to the c# winform to display instead of saving
is this enough info?
if you are new to programming this is going to be quite challenging
i know but i really gotta learn to do it
i mean i learned c before c++ but i haven't made a program this complex with it before
if anyone even knows the things i need to learn to do it it would be a great help
I'd just do the UI in C++ tbh
ohh it's easier that way?
then sure
Besides that, I guess you could use callbacks
so there is a way to send this image to a "display", how would that work?
Maybe. Not sure if a pointer to a function in C++ DLL would translate into a C#
Func<>
oh i meant in cpp
Well, you would start by making a C++ UI, with something like... dunno what's in use nowadays, ImGUI? QT?
ok, i'm trying to learn qt and it's beating my ass but yeah i'll use that then
so going with QT or imgui is smarter
Thanks to everyone here. I wanted to do it on c# because of not so good advice I got irl
i don’t think there is anything wrong with the idea, it is just more difficult than using that SDK from C++, and there needs to be a reason to take on that difficulty
if you are writing a large application where Windows Forms will be more productive than C++, it is worth spending a little bit of time figuring out the interop so you can use C# instead of C++
if you are just going to display the picture in a window, that is simple enough using a library like Qt that it’s easier to just do it all from C++, it will be a couple hundred lines of code at most
so in a bigger application it's better to use winform? and what i would need to learn is interop?
the program was simple, save an image and close but i'm going to build it quite a bit. then it would be better to learn what you callo interop?
what i'll do is display basically a video, every time a new image is acquired i'll show to screen, there will be some filters that can be applied on that image and some math stuff done to it so it looks good
but i guess that doesn't have much to do with winform, right?
std::string save_result = utilities::save_file(file_name, reinterpret_cast<const uint8_t>(image),
widthheight*sizeof(uint16_t));
basically i want to do this but inside the c# program, i guess it would be called display file and would put the data in a c# object that would be displayed
i already checked dllimport and stuff only thing is idk how i go about a virtual void acuired image sending info to the c# display
most people like using C# over C++. so, if the “application” is going to be a lot of code, it’s probably worth doing the setup so that you can write the application in C#
it is probably not that complicated
yes, you have to be a little bit clever
i cannot really help without knowing what the API looks like, though
i’m assuming it’s some kind of abstract class, and you (the person using the SDK) need to override image_acquired, right?
and is that all you need? or are there more functions you will need
For now yes, a friend will try to create a couple filters for the images but I don't think that is a problem for c# right? He would change the image pixel by pixel and then send I'd send it in the same way to the winform
Yeah, you can see the code above
yeah ok. when i get home i can explain what the interop will look like
you will have to write a little bit of your own C++
as the glue code that the C# will have access to
but the logic you should be able to do in C# fully
Oh perfect thanks
Where did you learn this? Also want to learn so i don't find myself stumped in a similar but different situation
can you explain what you do with the object? like, ok, you have the class which implements image_acquired, but what do you do with it? how do you make it do something
I just saved the image in a raw file for now
You can see the code above of how I saved the image I reveibed
yes, what i mean is, how do you hook up the class you made to the library
like. you have some kind of
class MyThing : public TheThing { virtual void image_acquired(...) { ... } }
what do you do with MyThing
Oh it's a class that's present in the library already
that method is your code, though, right? like, you wrote that, that's not the library
utilities::save_file
etc.that's already how the image in sent by through the sdk
device dev;
connect(dev);
// Connect
bool connect(device& dev)
{
std::string connect_error;
bool connect_result = dev.connect();
// SIXTeen SDK opens log file on any connect call.
// We want to print here log file name, both if connect succeeded or failed.
// First we need to call stn_device::get_last_error and remember it, since last error information
// is overridden on every device call.
if (!connect_result)
{
connect_error = utilities::stn_error_to_string("connect");
}
// Print log file name
const char* log_file_name{};
if (dev.get_log_file_name(log_file_name))
{
sync_print(FUNCTION, " Log file ", log_file_name);
}
if (!connect_result)
{
// Print dev.connect error
sync_print(connect_error);
return false;
}
// OK
sync_print(FUNCTION, " Device is connected");
return true;
}
bool acquire_images(device& dev)
{
if (!dev.start_acquisition())
{
sync_print(utilities::stn_error_to_string("start_acquisition"));
return false;
}
// Specifically, device::image_acquired is called as many times as it was set to per second #ifdef _WIN32 sync_print(FUNCTION, " Acquisition started. Press any key to stop"); _getch(); #else sync_print(FUNCTION, " Acquisition started. Enter any string to stop"); std::string s; std::cin >> s; #endif if (!dev.stop_acquisition()) { sync_print(utilities::stn_error_to_string("stop_acquisition")); return false; } sync_print(FUNCTION, " Acquisition stopped"); return true; } start_acquisition is an sdk function it calls device::image acquired @reflectronic makes sense? class device : public stn::stn_device { public: device(){}; virtual ~device(){} private: int image_index{}; protected: virtual void image_acquired(.......
// Specifically, device::image_acquired is called as many times as it was set to per second #ifdef _WIN32 sync_print(FUNCTION, " Acquisition started. Press any key to stop"); _getch(); #else sync_print(FUNCTION, " Acquisition started. Enter any string to stop"); std::string s; std::cin >> s; #endif if (!dev.stop_acquisition()) { sync_print(utilities::stn_error_to_string("stop_acquisition")); return false; } sync_print(FUNCTION, " Acquisition stopped"); return true; } start_acquisition is an sdk function it calls device::image acquired @reflectronic makes sense? class device : public stn::stn_device { public: device(){}; virtual ~device(){} private: int image_index{}; protected: virtual void image_acquired(.......
so you just and that's all you need to do?
yeah for now yess
maybe it's a stupid question but i'm new to object programming
ok. so, the first thing you would need is a class that allows C# to provide an implementation of image_acquired
it is not possible for C# to inherit a C++ class directly, so you need to provide some kind of wrapper in C++
it would look something like this, i think:
the
image_acquired_callback*
is a function pointer--this is what's going to let C# provide the function
you will write a function in C# and pass it to this code. then, you can see image_acquired
invoke that function pointer. that will allow it to call back into the C#
the next thing you will need is a way to create this object. you cannot create or delete a C++ class directly from C#, so you will need some helper functions that are callable from C#
you can see that the create_dotnet_device
takes in the callback (which C# will provide), and then it'll return back a pointer the dotnet_device
object. C# won't be able to use this pointer directly, but it'll be able to pass it to other functions which you define. (like, for example, delete_dotnet_device
, which will delete the object from memory once you are done with it.)
this creates the objects, but you need to actually call the functions start the acquisition. actually, you can probably do this inside of create_dotnet_device
... but of course you could split it into a different function. so, that would look like:
hm, actually, it's probably better to do it in different functions... so:
(i'm putting these try/catches because i don't know if this library uses exceptions)
anyway, this is all you need on the C++ side for the basic interop... you would put all of that code in a C++ project, compile it into a dll file. the extern "C"
and __declspec(dllexport)
things are the magic sauce that will make these functions available to C#
then, on the C# side, you can use P/Invoke to access these dllexport
ed functionsook
so now i can access image_acuired from c#
after using P/invoke on the c# side i have to create a function so that when the method acquired_image is called the winform displays the image right?
then, you could write a wrapper class over this:
and, so, finally, the way you would use this class is like this:
to put it all together you would copy the C++ DLL (which i assumed is named StnHelper.dll, but you can name it whatever you want and change the
DllImport
s) next to the build output of your windows forms
and then it would do the thing
if there is something you did not quite understand i can explain in more detailok, took a moment to process what exactly the code is doing
wnh is the class internal? would it not work otherwise?
no, there is no particular reason
the wrapper class should mean that you don’t need to use the native functions directly, though
I get a missing method exception
from where
The first one, handle= CreateDotNetDevice(callback)
what does the exception say
It's not giving much info tbh
Maybe the issue is in the connection between the cpp and c# code itself because it gives the same error without the cpp code
it definitely does not just say “MissingMethodException”
it gives more information
hm. can you replace with
.
sorry, i meant
Now it's dllnotfound exception
yes, now you need to copy the C++ DLL to the C# build output folder