Solved

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

Posted on 2009-04-09
19
2,635 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
Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

 
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

Free Tool: Postgres Monitoring System

A PHP and Perl based system to collect and display usage statistics from PostgreSQL databases.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
2 questions 10 29
how to double quote a string for an inline sql statement. 8 73
Graph API & MS Apps 1 22
Unlocking a column in excel using C# 17 18
After several hours of googling I could not gather any information on this topic. There are several ways of controlling the USB port connected to any storage device. The best example of that is by changing the registry value of "HKEY_LOCAL_MACHINE\S…
Performance in games development is paramount: every microsecond counts to be able to do everything in less than 33ms (aiming at 16ms). C# foreach statement is one of the worst performance killers, and here I explain why.
The viewer will learn how to pass data into a function in C++. This is one step further in using functions. Instead of only printing text onto the console, the function will be able to perform calculations with argumentents given by the user.
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.

856 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