• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 3072
  • Last Modified:

Share memory between a C++ program and a C# program

Hi all,

I currently have 2 c++ programs running windows, one that creates a file mapping object that shares some variables, and one that opens the file mapping object and takes the variables and uses them.

I need the second program to ultimately be a C# console app, but I cannot find any information online about sharing memory in C#. I'll post my C++ code that I ultimately need to port over to C#.

Does anyone know how I would go about doing this? Thanks for your help!
#define MAX			500
#define BUF_SIZE	256	
 
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <windows.h>
#include <conio.h>
#include <tchar.h>
#include <memory.h>
 
char szName[] = "Global\\MyFileMappingObject";
 
int main()
{
 
	printf("Client Simple Simulator\n");
 
	HANDLE hMapFile_1 = OpenFileMapping(
		FILE_MAP_ALL_ACCESS,
		FALSE,
		szName);
 
	LPCTSTR pBuf_1 = (LPTSTR)MapViewOfFile(
		hMapFile_1,
		FILE_MAP_ALL_ACCESS,
		0,
		0,
		BUF_SIZE);
 
	printf("\n%s\n", pBuf_1);
 
	getch();
 
	UnmapViewOfFile(pBuf_1);
	CloseHandle(hMapFile_1);
 
	return 0;
}

Open in new window

0
ehensens
Asked:
ehensens
  • 8
  • 7
  • 2
3 Solutions
 
jkrCommented:
I already posted a link to http://www.codeproject.com/KB/threads/sharedmemipc.aspx ("Interprocess Communication using Shared Memory") in your other question - you'll find the C# counterpart at http://www.codeproject.com/KB/threads/csthreadmsg.aspx ("A C# Framework for Interprocess Synchronization and Communication"). Tieing both these ends together, you have a C#/C++ IPC using shared memory.
0
 
ehensensAuthor Commented:
Hi jkr,

Sorry, for some reason I didn't get any email saying that you had posted a possible solution to my other question or I would have seen that link first. I'll check this out.
0
 
abelCommented:
You can do it the same way as in C++, if that feels most convenient for you, but in C# that means a little more work because you have to P/Invoke your win32 API functions. An example of how that's done for MapViewOfFile is found here: http://www.pinvoke.net/default.aspx/kernel32/MapViewOfFile.html

If you'll end up with C#-only applications in the end, you can also stick to MemoryStream, which is very simple way to use any stream in-memory only.

If you want to have access to direct memory locations, you can use the UnmanagedMemoryStream class in C#.

Depending on the end result you're after, you can choose either or a combination of these approaches.

-- Abel --
0
The new generation of project management tools

With monday.com’s project management tool, you can see what everyone on your team is working in a single glance. Its intuitive dashboards are customizable, so you can create systems that work for you.

 
abelCommented:
ah, I see jkr also posted some. In addition, I came across the following link claiming to have be a full wrapper for memory mapped files and interop services, it may save you some time: http://github.com/tomasr/filemap/tree/master
0
 
ehensensAuthor Commented:
Hi everyone, thanks so much for your help, but I fear that I am still doing something wrong. I am getting the following errors:

Error    1    The best overloaded method match for 'C_Sharp_Client_Simulator.Program.MapViewOfFile(System.IntPtr, C_Sharp_Client_Simulator.Program.FileMapAccess, uint, uint, uint)' has some invalid arguments

Error    2    Argument '2': cannot convert from 'uint' to 'C_Sharp_Client_Simulator.Program.FileMapAccess'

Can anyone spot what I'm doing wrong here?




using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
 
 
namespace C_Sharp_Client_Simulator
{
    class Program
    {
        [DllImport("kernel32.dll", SetLastError = true)]
        static extern IntPtr OpenFileMapping(
            uint dwDesiredAccess, 
            bool bInheritHandle,
            string lpName);
 
        [DllImport("kernel32.dll", SetLastError = true)]
        static extern IntPtr MapViewOfFile(
            IntPtr hFileMappingObject,
            FileMapAccess dwDesiredAccess,
            uint dwFileOffsetHigh,
            uint dwFileOffsetLow,
            uint dwNumberOfBytesToMap);
 
        [Flags]
        public enum FileMapAccess : uint
        {
            FileMapCopy = 0x0001,
            FileMapWrite = 0x0002,
            FileMapRead = 0x0004,
            FileMapAllAccess = 0x001f,
            fileMapExecute = 0x0020,
        }
 
        public static IntPtr Attach()
        {
            string szName = "Global\\MyFileMappingObject";
            uint BUF_SIZE = 256;
 
            UInt32 STANDARD_RIGHTS_REQUIRED = 0x000F0000;
            UInt32 SECTION_QUERY = 0x0001;
            UInt32 SECTION_MAP_WRITE = 0x0002;
            UInt32 SECTION_MAP_READ = 0x0004;
            UInt32 SECTION_MAP_EXECUTE = 0x0008;
            UInt32 SECTION_EXTEND_SIZE = 0x0010;
            UInt32 SECTION_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | SECTION_QUERY |
            SECTION_MAP_WRITE |
            SECTION_MAP_READ |
            SECTION_MAP_EXECUTE |
            SECTION_EXTEND_SIZE);
            UInt32 FILE_MAP_ALL_ACCESS = SECTION_ALL_ACCESS;
 
            IntPtr hMapFile_1 = OpenFileMapping(FILE_MAP_ALL_ACCESS, false, szName);
            IntPtr pBuf = MapViewOfFile(hMapFile_1, FILE_MAP_ALL_ACCESS, 0, 0, BUF_SIZE);
            return pBuf;
        }
 
 
        static int Main(string[] args)
        {
            Console.WriteLine("C# Client Simulator");
 
            IntPtr valueInMemory = Attach();
 
            Console.WriteLine("{0}", valueInMemory);
 
            Console.ReadLine();
 
            return 0;
        }
    }
}

Open in new window

0
 
ehensensAuthor Commented:
Update:

I have changed my code to the following, and I am at least getting it to compile, but I'm not familiar with IntPtr, and the return of the MapViewOfFile is of type IntPtr and when I console.writeline the return value it's just a long int. Can anyone lend some insight as to what I'm doing wrong here? Thanks a bunch!

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
 
 
namespace C_Sharp_Client_Simulator
{
    class Program
    {
        [DllImport("kernel32.dll", SetLastError = true)]
        static extern IntPtr OpenFileMapping(
            uint dwDesiredAccess,
            bool bInheritHandle,
            string lpName);
 
        
        [DllImport("kernel32.dll", SetLastError = true)]
        static extern IntPtr MapViewOfFile(
            IntPtr hFileMappingObject,
            uint dwDesiredAccess,
            uint dwFileOffsetHigh,
            uint dwFileOffsetLow,
            uint dwNumberOfBytesToMap);
 
        
        /*[Flags]
        public enum FileMapAccess : uint
        {
            FileMapCopy = 0x0001,
            FileMapWrite = 0x0002,
            FileMapRead = 0x0004,
            FileMapAllAccess = 0x001f,
            fileMapExecute = 0x0020,
        }*/
 
        public static void attach()
        {
            string szName = "Global\\MyFileMappingObject";
            uint BUF_SIZE = 256;
 
            UInt32 STANDARD_RIGHTS_REQUIRED = 0x000F0000;
            UInt32 SECTION_QUERY = 0x0001;
            UInt32 SECTION_MAP_WRITE = 0x0002;
            UInt32 SECTION_MAP_READ = 0x0004;
            UInt32 SECTION_MAP_EXECUTE = 0x0008;
            UInt32 SECTION_EXTEND_SIZE = 0x0010;
            UInt32 SECTION_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | SECTION_QUERY |
            SECTION_MAP_WRITE |
            SECTION_MAP_READ |
            SECTION_MAP_EXECUTE |
            SECTION_EXTEND_SIZE);
            UInt32 FILE_MAP_ALL_ACCESS = SECTION_ALL_ACCESS;
            uint AccessType = 0x001f;
            //FileMapAccess AccessType = FileMapAllAccess;
 
            IntPtr hMapFile_1 = OpenFileMapping(FILE_MAP_ALL_ACCESS, false, szName);
            IntPtr pBuf = MapViewOfFile(hMapFile_1, AccessType, 0, 0, BUF_SIZE);
 
            Console.WriteLine("\n{0}\n", pBuf);
        }
 
 
        static int Main(string[] args)
        {
            Console.WriteLine("C# Client Simulator");
 
            attach();
 
            //IntPtr valueInMemory = Attach();
 
            //Console.WriteLine("{0}", valueInMemory);
 
            Console.ReadLine();
 
            return 0;
        }
    }
}

Open in new window

0
 
abelCommented:
You can do one of two things from that code: either you use the constants, as you do in the calling of the function, in which case you should declare the function with uint for the flags. Or you use the enum, in which case you should both declare and use the enum.

I can understand that the example of that page is a bit blurred because it mixes both methods:




// change the calling of the method by using a typed enum
IntPtr pBuf = MapViewOfFile(hMapFile_1, FileMapAccess.FileMapAllAccess, 0, 0, BUF_SIZE);
 
//or change the declaration to use the untyped constants:
 
[DllImport("kernel32.dll", SetLastError = true)]
   static extern IntPtr MapViewOfFile(
      IntPtr hFileMappingObject,
      uint dwDesiredAccess,
      uint dwFileOffsetHigh,
      uint dwFileOffsetLow,
      uint dwNumberOfBytesToMap);

Open in new window

0
 
abelCommented:
just saw your last comment, but I'm off for two hours, will be back soon!
0
 
ehensensAuthor Commented:
So now that I get it to compile (see my code), I am printing out the value on the screen, which should be a char[] "hello" from my c++ program, but it's appearing each time as 6 or 7 digit numbers.

Anyone have any ideas? Please help out; if I can increase the amount of points beyond 500 please let me know how.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
 
 
namespace C_Sharp_Client_Simulator
{
    class Program
    {
        [DllImport("kernel32.dll", SetLastError = true)]
        static extern IntPtr OpenFileMapping(
            uint dwDesiredAccess,
            bool bInheritHandle,
            string lpName);
 
        
        [DllImport("kernel32.dll", SetLastError = true)]
        static extern IntPtr MapViewOfFile(
        //static extern string MapViewOfFile(
            IntPtr hFileMappingObject,
            uint dwDesiredAccess,
            uint dwFileOffsetHigh,
            uint dwFileOffsetLow,
            uint dwNumberOfBytesToMap);
 
        public static void attach()
        {
            string szName = "Global\\MyFileMappingObject";
            uint BUF_SIZE = 256;
 
            UInt32 STANDARD_RIGHTS_REQUIRED = 0x000F0000;
            UInt32 SECTION_QUERY = 0x0001;
            UInt32 SECTION_MAP_WRITE = 0x0002;
            UInt32 SECTION_MAP_READ = 0x0004;
            UInt32 SECTION_MAP_EXECUTE = 0x0008;
            UInt32 SECTION_EXTEND_SIZE = 0x0010;
            UInt32 SECTION_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | SECTION_QUERY |
            SECTION_MAP_WRITE |
            SECTION_MAP_READ |
            SECTION_MAP_EXECUTE |
            SECTION_EXTEND_SIZE);
            UInt32 FILE_MAP_ALL_ACCESS = SECTION_ALL_ACCESS;
            uint AccessType = 0x001f;
 
            IntPtr hMapFile_1 = OpenFileMapping(FILE_MAP_ALL_ACCESS, false, szName);
            //string pBuf = MapViewOfFile(hMapFile_1, AccessType, 0, 0, BUF_SIZE);
            IntPtr pBuf = MapViewOfFile(hMapFile_1, AccessType, 0, 0, BUF_SIZE);
 
            Console.WriteLine(pBuf);
        }
 
 
        static int Main(string[] args)
        {
            Console.WriteLine("C# Client Simulator");
 
            attach();
 
            Console.ReadLine();
 
            return 0;
        }
    }
}

Open in new window

0
 
ehensensAuthor Commented:
got it. the fix is:

string pBufString = System.Runtime.InteropServices.Marshal.PtrToStringAnsi(pBuf);
0
 
abelCommented:
Sorry, like I said, i needed to run. Just got back. Glad you found it out. Note that you should use

System.Runtime.InteropServices.Marshal.PtrToStringUni

in many cases if the contents goes beyond the first 127 characters of US-ASCII. That is, because the Ansi (8 bit) is there still for old style strings and storage, but on win32 windows, all strings and data is commonly stored in utf-8 or utf-16 (in memory, all strings are utf-16). Using PtrToStringUni can be a lot saver and save you from trouble in the future when some é, ä, æ or å pops up incorrectly encoded showing as a different character....

-- Abel --
0
 
ehensensAuthor Commented:
Thanks for everyone's help, I am really busy now but after the long weekend I will divvy up the points.
0
 
jkrCommented:
So, the above articles didn't help at all?
0
 
abelCommented:
I think it did. See a few comments back, where the OP says "got it. the fix is:". On that point, I continued slightly. Why the OP didn't at least share the points is beyond me. Shall I post a request for split?

-- Abel --
0
 
ehensensAuthor Commented:
Sorry, how do I change it now?
0
 
abelCommented:
you can do so by clicking the "Request Attention" link, right under your question. You can then type a small message to the moderators, including the IDs of the comments you want to split between and they will change it for you.
0
 
ehensensAuthor Commented:
That would be great, jkr, thanks.
0

Featured Post

The new generation of project management tools

With monday.com’s project management tool, you can see what everyone on your team is working in a single glance. Its intuitive dashboards are customizable, so you can create systems that work for you.

  • 8
  • 7
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now