Solved

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

Posted on 2009-04-09
19
2,678 Views
Last Modified: 2013-12-03
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
Comment
Question by:ehensens
  • 8
  • 7
  • 2
19 Comments
 
LVL 86

Assisted Solution

by:jkr
jkr earned 150 total points
ID: 24108028
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
 

Author Comment

by:ehensens
ID: 24108066
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
 
LVL 39

Assisted Solution

by:abel
abel earned 350 total points
ID: 24108071
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
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 39

Expert Comment

by:abel
ID: 24108100
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
 

Author Comment

by:ehensens
ID: 24108603
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
 

Author Comment

by:ehensens
ID: 24109271
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
 
LVL 39

Accepted Solution

by:
abel earned 350 total points
ID: 24109331
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
 
LVL 39

Expert Comment

by:abel
ID: 24109343
just saw your last comment, but I'm off for two hours, will be back soon!
0
 

Author Comment

by:ehensens
ID: 24110126
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
 

Author Comment

by:ehensens
ID: 24110335
got it. the fix is:

string pBufString = System.Runtime.InteropServices.Marshal.PtrToStringAnsi(pBuf);
0
 
LVL 39

Expert Comment

by:abel
ID: 24111075
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
 

Author Comment

by:ehensens
ID: 24111091
Thanks for everyone's help, I am really busy now but after the long weekend I will divvy up the points.
0
 
LVL 86

Expert Comment

by:jkr
ID: 24169936
So, the above articles didn't help at all?
0
 
LVL 39

Expert Comment

by:abel
ID: 24170417
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
 

Author Comment

by:ehensens
ID: 24170674
Sorry, how do I change it now?
0
 
LVL 39

Expert Comment

by:abel
ID: 24170786
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
 

Author Comment

by:ehensens
ID: 24172296
That would be great, jkr, thanks.
0

Featured Post

Instantly Create Instructional Tutorials

Contextual Guidance at the moment of need helps your employees adopt to new software or processes instantly. Boost knowledge retention and employee engagement step-by-step with one easy solution.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Entity Framework is a powerful tool to help you interact with the DataBase but still doesn't help much when we have a Stored Procedure that returns more than one resultset. The solution takes some of out-of-the-box thinking; read on!
It was really hard time for me to get the understanding of Delegates in C#. I went through many websites and articles but I found them very clumsy. After going through those sites, I noted down the points in a easy way so here I am sharing that unde…
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.

733 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question