从内存映射文件中读取数据时出现问题

6

我正在尝试在我的应用程序(特别是Windows服务)中实现一个内存映射文件,然后使用C#表单从MMF中读取服务写入的内容。不幸的是,我似乎无法让表单从MMF中读取任何内容,更重要的是,表单似乎永远找不到服务创建的MMF。以下是概述我所做的内容的代码片段,有人能看出我做错了什么或者能够指导我更好的方向吗?

服务:

private MemoryMappedFile mmf = MemoryMappedFile.CreateOrOpen("AuditStream", 1024 * 1024);
private Mutex mutex = new Mutex(false, "MyMutex");

byte[] msg = new byte[1];
var view = mmf.CreateViewStream(0, 1);
byte[] rmsg = new byte[1];

for (int i = 0; i < 400; i++)
{
     mutex.WaitOne();
     for (int j = 0; j < msg.Length; j++)
     {
          msg[j] = (byte)i;
     }

     view.Position = 0;
     view.Write(msg, 0, bufferSize);

     //the next 3 lines verify that i wrote to the mmf and can potentially read from it
     //These are just for testing
     view.Position = 0;
     view.Read(rmsg, 0, 1);
     Log.Error("Finished MMF", rmsg[0].ToString());

     mutex.ReleaseMutex();
 }

表单:

private MemoryMappedFile mmf;
private Mutex mutex;
Thread t = new Thread(MmfMonitor);
t.Start();

private void MmfMonitor()
    {

        byte[] message = new byte[1];
        while(!quit)
        {
            try
            {
                **mmf = MemoryMappedFile.OpenExisting("AuditStream");**
                mutex = Mutex.OpenExisting("MyMutex");
                var view = mmf.CreateViewStream(0, 1);

                mutex.WaitOne();
                view.Position = 0;
                view.Read(message, 0, 1);
                Invoke(new UpdateLabelCallback(UpdateLabel), message[0].ToString());
                mutex.ReleaseMutex();
            }catch(FileNotFoundException)
            {
                **//The AuditStream MMF is never found, and therefore doesnt every see the proper values**
            }
        }
    }

此外,在服务“运行”时,MMF 应始终具有句柄,并且不应被垃圾回收器收回;

那么,你确实收到了FileNotFoundException异常吗? - Peter Ritchie
表单exe是否与服务在同一目录中?有时服务的默认目录是c:\ windows \ system32。我会尝试指定文件的完整路径,而不是像“AuditStream”这样的相对路径。 - Peter Ritchie
1
服务运行在哪个账户下? - HABO
@ Peter - 是的,我收到了FileNotFoundException的错误信息,但是表单并不在服务所在的同一目录中,因为它是一个完全独立的项目。由于这是共享内存空间而不是特定的文件,因此除了名称之外,没有其他的“路径”。 - Zholen
@HABO,如果这是一个权限问题,我会期望出现访问被拒绝的异常... - Peter Ritchie
1个回答

14

该服务运行在不同的会话中,即著名的“session 0”。Windows对象存在于与进程会话关联的名称空间中,因此您的表单无法看到在服务使用的会话中创建的对象。

您必须在mmf名称前添加Global\,以在全局命名空间中创建和访问对象。

因此,在服务中:

mmf = MemoryMappedFile.CreateOrOpen(@"Global\AuditStream", ...)

并且以以下形式:

mmf = MemoryMappedFile.OpenExisting(@"Global\AuditStream");

谢谢,这样就可以了!现在我只需要解决那个访问被拒绝的错误。 - Zholen
我想为任何查看此帖子的其他人添加一条提示,不要忘记对您的互斥锁(“Global”)执行相同的操作,因为一旦您可以看到流,您很可能会遇到访问问题。以下是一种解决方法,尽管它确实使其非常“开放”: - Zholen
8
var security = new MemoryMappedFileSecurity(); security.AddAccessRule(new AccessRule<MemoryMappedFileRights>("everyone", MemoryMappedFileRights.FullControl, AccessControlType.Allow)); mmf = MemoryMappedFile.CreateOrOpen(@"Global\AmToteAuditStream", 1024 * 1024, MemoryMappedFileAccess.ReadWrite, MemoryMappedFileOptions.DelayAllocatePages,security, HandleInheritability.Inheritable );这段代码创建了一个内存映射文件对象,并加入了权限规则以便所有人都能够完全控制该对象。其中的字符串@"Global\AmToteAuditStream"是该对象的名称,1024*1024表示该对象的大小为1MB。MemoryMappedFileAccess.ReadWrite表示可读可写,MemoryMappedFileOptions.DelayAllocatePages表示延迟分配页面,HandleInheritability.Inheritable表示可以继承句柄。 - Zholen
@Zholen,你最后的评论解决了访问被拒绝的异常吗? - WBuck

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接