假设我把一片Memory或者一个文件的一部分映射为"c:\test.txt"
然后另一个进程直接读"c:\test.txt"的内容呢?
注意仅仅是映射而不是写入"c:\test.txt"不想用IPC共享内存,我的思路是否可行?请指点。

解决方案 »

  1.   

    映射可以,但是windows无法和delphi的stream通信,想把stream映射成其他进程可以访问的共享资源是不可能的。只能把你的stream的东西拷贝到另外建立好的映射文件中再跟其他进程共享。对于文件和文件的一部分是可以的,但是不需要映射成另外一个文件。因为访问映射内容的时候都是依靠一个指针。我写了个映射文件的Stream类,可能有点牵强,但是我想能避免你用流的时候额外拷贝到英社区的操作,因为你可以直接用“内存映射流类”的实例代替原来的任何流类。晚上给你贴出来。
      

  2.   

    unit FileMapStream_san;interface
    uses
    windows,classes,sysutils;const
    c_memhandle=$FFFFFFFF;
    c_msg_cannotsetsize='Cannot set the size of a "%s" object, except for setting the "%s" property to True.';type
      TProtection_san=(pREAD,pREADWRITE,pCOPY);
      TAdditionalProtection_san=(apCOMMIT,apIMAGE,apNOCACHE,apRESERVE);
      TAdditionalProtections_San=set of tadditionalprotection_san;
      TFileMapStream_San=class(TStream)
      private
        FFileHandle:cardinal;
        FMapHandle:cardinal;
        FStartPointer:pointer;
        FCurrentPointer:pointer;
        FMapName:string;
        FSize:cardinal;
        FProtection:TProtection_San;
        fAdditionalProtections:TAdditionalProtections_san;
        FAlreadyExists:boolean;
        //////////
        FInitializing:boolean;
      protected
        procedure SetSize(NewSize: Longint); overload; override;
        function StartPointer():pointer;
        function CurrentPointer():pointer;    
      public
        AutoSize:boolean;
        ////////////////////
        function Read(var Buffer; Count: Longint): Longint;  override;
        function Write(const Buffer; Count: Longint): Longint; override;
        function Seek(Offset: Longint; Origin: Word): Longint; override;    constructor Create(const AMapName:string='';ASize: cardinal=0;AHandle: cardinal=c_memhandle;
        AProtection:TProtection_San=pREADWRITE;AAdditionalProtections:TAdditionalProtections_San=[]);
        destructor Destroy;override;    class function FileMapExists(AMapName:string):boolean;
        function ToString:string;  published
        property FileHandle:cardinal read ffilehandle;
        property MapHandle:cardinal read fmaphandle;
        property MapName:string read fmapname;
        property Protection:tprotection_san read fprotection;
        property AdditionalProtection:Tadditionalprotections_san read fadditionalprotections;
        property AlreadyExists:boolean read falreadyexists;
      end;implementation{ TFileMapStream_San }constructor TFileMapStream_San.create(const AMapName:string;ASize: cardinal;AHandle: cardinal;
        AProtection:TProtection_San;AAdditionalProtections:TAdditionalProtections_San);
    var
    n:pchar;
    p,p1:cardinal;
    begin
      FInitializing:=true;  ffilehandle:=ahandle;
      fmapname:=amapname;  fprotection:=aprotection;
      fadditionalprotections:=aadditionalprotections;
      autosize:=asize<=0;
      self.setsize(asize);end;procedure TFileMapStream_San.SetSize(NewSize: Integer);
    var
    n:pchar;
    p1,p:cardinal;
    begin
      if (not autosize)and(not FInitializing) then
        raise exception.Create(format(c_msg_cannotsetsize,[classname,'AutoSize']));
      if newsize<0 then newsize:=0;
      if (newsize=size) and (newsize<>0) then exit;
      
      fsize:=newsize;
      unmapviewoffile(fstartpointer);
      closehandle(fmaphandle);
                                   
      if fmapname='' then
        n:=nil
      else
        n:=pchar(fmapname);          p:=0;
      p1:=0;
      
      if fprotection=pread then
      begin
        p:=page_readonly;
        p1:=FILE_MAP_READ;  end;
      if preadwrite = fprotection then
      begin
        p:=page_readwrite;
        p1:= FILE_MAP_WRITE ;
      end;
      if pcopy = fprotection then
      begin
        p:= page_writecopy;
        p1:= FILE_MAP_COPY;
      end;
      if apCommit in  fadditionalprotections then p:=p or sec_commit;
      if apImage in  fadditionalprotections then p:=p or sec_image;
      if apNocache in  fadditionalprotections then p:=p or sec_nocache;
      if apReserve in  fadditionalprotections then p:=p or sec_reserve;  
     
      fmaphandle:=createfilemapping(ffilehandle,nil,p,0,fsize,n);  if (fmaphandle=0) then
      begin
        RaiseLastOSError;
      end else
      begin
        self.FAlreadyExists:=getlasterror=ERROR_ALREADY_EXISTS;
        
        FstartPointer:=mapviewoffile(fmaphandle,p1,0,0,0);
        if fstartpointer=nil then RaiseLastOSError;
       
        fcurrentpointer:=fstartpointer;
      end;
      FInitializing:=false;
    end;destructor TFileMapStream_San.Destroy;
    begin
      unmapviewoffile(fstartpointer);
      closehandle(fmaphandle);
      //msg;
      inherited;
    end;class function TFileMapStream_San.FileMapExists(AMapName: string): boolean;
    var
    n:pchar;
    h:cardinal;
    begin
      if amapname='' then
        n:=nil
      else
        n:=pchar(amapname);
      h:=createfilemapping(c_memhandle,nil,page_readonly,0,1,n);
      result:=(h<>0)and(getlasterror=ERROR_ALREADY_EXISTS);
      closehandle(h);
    end;function TFileMapStream_San.StartPointer(): pointer;
    begin
      result:=fstartpointer;
    end;function TFileMapStream_San.Read(var Buffer; Count: Integer): Longint;
    var
    c:cardinal;
    begin
      c:=size-position;
      if c>count then
        result:=count
      else
        result:=c;
        
      copymemory(@buffer,fcurrentpointer,result);
      position:=position+result;
    end;function TFileMapStream_San.Write(const Buffer; Count: Integer): Longint;
    var
    p:pointer;
    begin
      p:=fcurrentpointer;
      self.setsize(position+count);  fcurrentpointer:=p;
      copymemory(fcurrentpointer,@buffer,count);
      position:=position+count;
      result:=count;
    end;function TFileMapStream_San.Seek(Offset: Integer; Origin: Word): Longint;
    begin  case origin of
      soFromBeginning:
      begin
        result:=offset;
      end;
      soFromEnd:
      begin
        result:=fsize+offset;
      end;
      soFromCurrent:
      begin
        result:=cardinal(fcurrentpointer)-cardinal(fstartpointer)+offset;
      end;
      end;
      fcurrentpointer:=pointer(cardinal(fstartpointer)+result);
      if result<0 then
        result:=0
      else  if result>fsize then result:=fsize;end;
    function TFileMapStream_San.CurrentPointer(): pointer;
    begin
      result:=fcurrentpointer;
    end;function TFileMapStream_San.ToString: string;
    begin
      setlength(result,size);
      copymemory(@result[1],fstartpointer,size);
    end;end.
      

  3.   

    我不知道怎样得到已经存在的内存映象的信息比如他的大小等不然这个类就完善了。你可以用来代替原来的stream,或者用它来映射文件,只要在create里面设置handle是你打开的文件的handle就可以,打开文件的时候一定要注意保护模式不要和创建参数有冲突。当时设计的用handle而不是直接一个文件名,些两个overload的constructor就好了,一个专门用于内存,一个专门用于文件。其实就是多了个openfile调用而已,对于内存映射就是handle传入$ffffffff,懒得封装了。希望对你有用。
      

  4.   

    内存映像的特点似乎不适合封装成流,尤其是setsize的时候有些牵强,还有就是不好得到已经创建的映像的信息。也可能是鄙人驽钝,不知道ms提供这样的方法。哪位知道请赐教!
      

  5.   

    好奇怪啊,只是一个内存数据公用就这么麻烦,你丢到剪切板上不就行了。或者直接让第二个程序使用第一个程序的函数(dll)即可啊.
      

  6.   

    Thanks to stanely(俺是邢她汉子) !