1

I wish to pass an image pointer from a C# program to a C++ program, then the C++ program to generate a cv::Mat image and write the image to the disk to verify that it receives the correct image. However, I got an error of Read access violation. Which part of my code is wrong?

I am referring to the code and has modified from here. Attached below is the main code:

Server.cs

const uint BUFFER_SIZE = 1024;
string strMapFileName = "SharedMemory_CPP_CSHARP";
IntPtr pBuf;
IntPtr hMapFile;

hMapFile = FileMappingNative.CreateFileMapping(
    (IntPtr)FileMappingNative.INVALID_HANDLE_VALUE, IntPtr.Zero, 
    FileProtection.PAGE_READWRITE, 0, BUFFER_SIZE, strMapFileName);
pBuf = FileMappingNative.MapViewOfFile(
    hMapFile, FileMapAccess.FILE_MAP_ALL_ACCESS, 0, 0, BUFFER_SIZE);

System.Drawing.Bitmap bm = new System.Drawing.Bitmap("<imagePath>/image.jpg");
System.Drawing.Imaging.BitmapData bmpData = bm.LockBits(
    new System.Drawing.Rectangle(0, 0, bm.Width, bm.Height),
        System.Drawing.Imaging.ImageLockMode.ReadWrite,
        System.Drawing.Imaging.PixelFormat.Format24bppRgb);
Marshal.Copy(new IntPtr[] { bmpData.Scan0 }, 0, pBuf, 1);

Client.cpp

#define BUF_SIZE 1024
TCHAR szName[] = TEXT("SharedMemory_CPP_CSHARP");
HANDLE hMapFile;
char* pBuf;

hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, szName);
pBuf = (char*)MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, BUF_SIZE);

wchar_t pstrDest[BUF_SIZE];
int len = mblen(NULL, MB_CUR_MAX);
int nLen = len * strlen(pBuf);
mbtowc(pstrDest, pBuf, nLen + 1);
cv::Mat buf = cv::Mat(100, 100, CV_8UC1, pstrDest);
cv::imwrite("<iamgePath>/image1.jpg", buf);
xylieong
  • 11
  • 2

1 Answers1

0

I have no idea why you are manually copying bits out of Bitmap nor why you are creating a memory-mapped file using PInvoke, as both of these are prone to many errors.

For example, you are probably getting an access violation due to the fact you are sending the buffer pointer to the MM file, rather than the actual data, and the way you read it on the C++ side also looks suspicious. There are also memory leaks in a number of places.

You can do this much more simply with MemoryMappedFile and Bitmap.Save.

const uint BUFFER_SIZE = 1024;   // sounds a bit small
string strMapFileName = "SharedMemory_CPP_CSHARP";

using (var bm = new System.Drawing.Bitmap("<imagePath>/image.jpg"))
using (var file = MemoryMappedFile.CreateOrOpen(strMapFileName, BUFFER_SIZE, MemoryMappedFileAcces.ReadWrite))
using (var stream = file.CreateViewStream())
{
    bm.Save(stream, ImageFormat.Png);
}
Charlieface
  • 52,284
  • 6
  • 19
  • 43
  • Hi @Charlieface, are you suggesting that I send actual data of the image instead of its pointer? Won't this method require a lot more buffer size? – xylieong Aug 23 '22 at 08:29
  • Yes, that's why I said it was a bit small. You can't send just the pointer, as it has no meaning in another process. – Charlieface Aug 23 '22 at 11:14
  • Got it. Besides, can you show how my cpp client can get image data from the memory file? I am doing this `cv::Mat buf = cv::Mat(100, 100, CV_8UC1, pBuf);` , the program is saving image but it the image makes no sense at all and is wrong. I've read that we need to make use of "offset of the mapped view" from [link](https://stackoverflow.com/questions/2536331/most-efficient-way-to-send-images-across-processes). Can you show how I can do that? – xylieong Aug 24 '22 at 02:13
  • No I'm afraid I don't know much about C++'s image capabilities, although I would imagine you could use GDI+. I would guess you probably want to set the size of the MM file, then C++ could receive that correctly – Charlieface Aug 24 '22 at 05:30