Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

FileMapping class



  • Please log in to reply
6 replies to this topic
Learning one
  • Members
  • 1483 posts
  • Last active: Jan 02 2016 02:30 PM
  • Joined: 04 Apr 2009

WARNING: This is old thread. It is continued here.

This is one of those unpopular "can you make me a script" questions, but I can't resist to ask it... shy.png
I'm trying to make a simple File Mapping class based MSDN info and HotKeyIt's post. Here's what I have done for now:
 
Class:


Class FileMappingClass {
	; http://msdn.microsoft.com/en-us/library/windows/desktop/aa366556(v=vs.85).aspx
	; http://www.autohotkey.com/board/topic/86771-i-want-to-share-var-between-2-processes-how-to-copy-memory-do-it/#entry552031
	static INVALID_HANDLE_VALUE := -1, PAGE_READWRITE := 0x4, FILE_MAP_ALL_ACCESS := 0xF001F, BUF_SIZE:=10000

	__New(szName="Global\MyFileMappingObject") {	; Opens existing or creates new file mapping object
		hMapFile := DllCall("OpenFileMapping", "Ptr", this.FILE_MAP_ALL_ACCESS, "Int", 0, "Str", szName)
		if ( hMapFile == 0 ) { ; OpenFileMapping Failed - file mapping object doesn't exist - that means we have to create it
			hMapFile := DllCall("CreateFileMapping", "Ptr", this.INVALID_HANDLE_VALUE, "Ptr", 0, "Int", this.PAGE_READWRITE, "Int", 0, "Int", this.BUF_SIZE, "Str", szName)
			if ( hMapFile == 0 ) ; CreateFileMapping Failed
				return
		}
		pBuf := DllCall("MapViewOfFile", "Ptr", hMapFile, "Int", this.FILE_MAP_ALL_ACCESS, "Int", 0, "Int", 0, "Ptr", this.BUF_SIZE)
		if ( pBuf == 0 )	; MapViewOfFile Failed
			return
		this.szName := szName, this.hMapFile := hMapFile, this.pBuf := pBuf
	}
	Write(szMsg) {
		if (this.pBuf != "") {
			StrPut(szMsg, this.pBuf, this.BUF_SIZE)
			/*
				szMsgLen := StrLen(szMsg) * ( A_Isunicode ? 2 : 1 )
				szBufLen := StrLen(StrGet(this.pBuf)) * ( A_Isunicode ? 2 : 1 )
				MsgLen := (szMsgLen > szBufLen) ? szMsgLen : szBufLen
				if (MsgLen <= this.BUF_SIZE)
					DllCall("RtlMoveMemory", "Ptr", this.pBuf, "Ptr", &szMsg, "Ptr", MsgLen)
			*/
		}
	}
	Read() {
		return StrGet(this.pBuf)
	}
	Close() {
		DllCall("UnmapViewOfFile", "Ptr", this.pBuf), DllCall("CloseHandle", "Ptr", this.hMapFile)
		this.szName := "", this.BUF_SIZE := "", this.hMapFile := "", this.pBuf := ""
	}
	__Delete() {
		this.Close()
	}
}

Test script 1:


FM := new FileMappingClass()
return

F1::FM.Write(A_Sec " - written by " A_ScriptName)
F2::MsgBox,,, % FM.Read(), 1
F3::ExitApp
F4::FM.Close()
#Include FileMappingClass

Test script 2:


FM := new FileMappingClass()
return

1::FM.Write(A_Sec " - written by " A_ScriptName)
2::MsgBox,,, % FM.Read(), 1
3::ExitApp
4::FM.Close()
#Include FileMappingClass

Test works fine, but to be honest, I know very little about FileMapping + I'm not good enough in DllCalls & memory stuff, and that's why I'm not sure is this class a complete disaster or there is a hope... shy.png The class is really in a simple form; there's no semaphore or some other synchronization object, buf size is fixed, etc...
So what do you think about this class? Does it make any sense? Actually, my main request is: could you please make it better?


My Website • Recommended: AutoHotkey Unicode 32-bit • Join DropBox, Copy


HotKeyIt
  • Moderators
  • 7439 posts
  • Last active: Jun 22 2016 09:14 PM
  • Joined: 18 Jun 2008

Some comments:

- static vars are only used inside _New method so no need to place them in base object.

- BUF_SIZE as optional parameter

- on error no object should be returned so we don't need to check for this.pBuf in Write method

- Use internal __Set and __Get methods for read and write as well as __Delete for Close ( so object will be cleared automatically)

 

 

Here is a modified version with new features:

 - using __New method we can open further files and access them using object syntax, e.g. FM.__New("Global\NewFile")

 - support alias, so FM.__New("Global\NewFile:MyFile") will allow access to file using FM.MyFile.

 

Example using DynaRun(), but you can also copy each script to separate file.

DynaRun("
(
#include <FileMapping>
FM := new FileMapping(""Global\File1:f1"")
FM.__New(""Global\File2:f2"")
return
1::FM.f1:=A_Sec "" - written by "" A_ScriptName,FM.f2:=A_TickCount "" - written by "" A_ScriptName
2::MsgBox,,, `% FM.f1, 1
3::MsgBox,,, `% FM.f2, 1
4::FM.f1:="""",FM.f2:=""""
5::ExitApp
)","Script 1")
DynaRun("
(
#include <FileMapping>
FM := new FileMapping(""Global\File1:f1"")
FM.__New(""Global\File2:f2"")
return
F1::FM.f1:=A_Sec "" - written by "" A_ScriptName,FM.f2:=A_TickCount "" - written by "" A_ScriptName
F2::MsgBox,,, `% FM.f1, 1
F3::MsgBox,,, `% FM.f2, 1
F4::FM.f1:="""",FM.f2:=""""
F5::ExitApp
)","Script 2")

FileMapping Class:

Class FileMapping {
  ; http://msdn.microsoft.com/en-us/library/windows/desktop/aa366556%28v=vs.85%29.aspx
  ; http://www.autohotkey.com/board/topic/86771-i-want-to-share-var-between-2-processes-how-to-copy-memory-do-it/#entry552031

  __New(szName:="Global\MyFileMappingObject", BUF_SIZE:=10000) {
   
    static INVALID_HANDLE_VALUE := -1, PAGE_READWRITE := 0x4, FILE_MAP_ALL_ACCESS := 0xF001F
    If InStr(szName,":")
      szAlias:=SubStr(szName,InStr(szName,":")+1),szName:=SubStr(szName,1,InStr(szName,":")-1)
    hMapFile := DllCall("OpenFileMapping", "Ptr", FILE_MAP_ALL_ACCESS, "Int", 0, "Str", szName)
    if ( hMapFile == 0 ) { ; OpenFileMapping Failed - file mapping object doesn't exist - that means we have to create it
      hMapFile := DllCall("CreateFileMapping", "Ptr", INVALID_HANDLE_VALUE, "Ptr", 0, "Int", PAGE_READWRITE, "Int", 0, "Int", BUF_SIZE, "Str", szName)
      if ( hMapFile == 0 ) ; CreateFileMapping Failed
        return 0
    }
    pBuf := DllCall("MapViewOfFile", "Ptr", hMapFile, "Int", FILE_MAP_ALL_ACCESS, "Int", 0, "Int", 0, "Ptr", BUF_SIZE)
    if ( pBuf == 0 ) ; MapViewOfFile Failed
      return 0
    ObjInsert(this,"?" (szAlias?szAlias:szName), {name:szName,file:hMapFile,buf:pBuf,size:BUF_SIZE,base:{"__Delete":FileMapping.__Delete}})
  }
  __SET(szName,szMsg:="") {
    If !this.HasKey("?" szName)
      Return
      DllCall("RtlMoveMemory", "Ptr", this["?" szName].buf, "Ptr", &szMsg, "Ptr", (MsgLen:=StrLen(szMsg) * ( A_Isunicode ? 2 : 1 ))>this["?" szName].size?this["?" szName].size:MsgLen)
      return szMsg
  }
  __GET(szName) {
    If this.HasKey("?" szName)
      return StrGet(this["?" szName].buf)
  }
  __Delete() {
    If this.HasKey("buf")
      DllCall("UnmapViewOfFile", "Ptr", this.buf), DllCall("CloseHandle", "Ptr", this.file)
  }
}


Learning one
  • Members
  • 1483 posts
  • Last active: Jan 02 2016 02:30 PM
  • Joined: 04 Apr 2009

Thank you HotKeyIt! wink.png
 
Can I replace this line

DllCall("RtlMoveMemory", "Ptr", this["?" szName,"buf"], "Ptr", &szMsg, "Ptr", (MsgLen:=StrLen(szMsg) * ( A_Isunicode ? 2 : 1 ))>this["?" szName,"size"]?this["?" szName,"size"]:MsgLen)

with this?

StrPut(szMsg, this["?" szName,"buf"], this["?" szName,"size"])

My Website • Recommended: AutoHotkey Unicode 32-bit • Join DropBox, Copy


HotKeyIt
  • Moderators
  • 7439 posts
  • Last active: Jun 22 2016 09:14 PM
  • Joined: 18 Jun 2008

It should be:

StrPut(szMsg, this["?" szName,"buf"], (MsgLen:=StrLen(szMsg) * ( A_Isunicode ? 2 : 1 ))>this["?" szName,"size"]?this["?" szName,"size"]:MsgLen)


Learning one
  • Members
  • 1483 posts
  • Last active: Jan 02 2016 02:30 PM
  • Joined: 04 Apr 2009
✓  Best Answer

Thanks. cool.png   Although your version is better and has more features, I think I'll end up with this;

/*
;====== Test script 1 ======
FM := new FileMapping()
F1::FM.Write(A_Sec " - written by " A_ScriptName)
F2::MsgBox,,, % FM.Read(), 1
F3::FM.Write()    ; delete all
F4::FM:=""
F5::MsgBox,,, % IsObject(FM), 1
Esc::ExitApp
*/

/*
;====== Test script 2 ======
FM := new FileMapping()
1::FM.Write(A_Sec " - written by " A_ScriptName)
2::MsgBox,,, % FM.Read(), 1
3::FM.Write()    ; delete all
4::FM:=""
5::MsgBox,,, % IsObject(FM), 1
Esc::ExitApp
*/

Class FileMapping {    ; Credits: HotKeyIt, billy036, Learning one. http://www.autohotkey.com/board/topic/93305-filemapping-class/#entry588351
    ; http://msdn.microsoft.com/en-us/library/windows/desktop/aa366556(v=vs.85).aspx
    ; http://www.autohotkey.com/board/topic/86771-i-want-to-share-var-between-2-processes-how-to-copy-memory-do-it/#entry552031
    ; http://www.autohotkey.com/board/topic/93305-filemapping-class/

    __New(Name="Global\MyFileMappingObject", BufSize=10000) {    ; Opens existing or creates new file mapping object
        static INVALID_HANDLE_VALUE := -1, PAGE_READWRITE := 0x4, FILE_MAP_ALL_ACCESS := 0xF001F
        hMapFile := DllCall("OpenFileMapping", "Ptr", FILE_MAP_ALL_ACCESS, "Int", 0, "Str", Name)
        if ( hMapFile == 0 ) {        ; OpenFileMapping Failed - file mapping object doesn't exist - that means we have to create it
            hMapFile := DllCall("CreateFileMapping", "Ptr", INVALID_HANDLE_VALUE, "Ptr", 0, "Int", PAGE_READWRITE, "Int", 0, "Int", BufSize, "Str", Name)
            if ( hMapFile == 0 )    ; CreateFileMapping Failed
                return
        }
        pBuf := DllCall("MapViewOfFile", "Ptr", hMapFile, "Int", FILE_MAP_ALL_ACCESS, "Int", 0, "Int", 0, "Ptr", BufSize)
        if ( pBuf == 0 )    ; MapViewOfFile Failed
            return
        this.Name := Name, this.hMapFile := hMapFile, this.pBuf := pBuf, this.BufSize := BufSize
    }
    Write(String="") {    ; ommiting the String param has "delete all" effect
        if (StrLen(String)*(A_Isunicode ? 2 : 1) <= this.BufSize) {
            Num := StrPut(String, this.pBuf)
            return Num
        }
    }
    Read() {
        return StrGet(this.pBuf)
    }
    __Delete() {
        DllCall("UnmapViewOfFile", "Ptr", this.pBuf), DllCall("CloseHandle", "Ptr", this.hMapFile)
    }
}

Could you please look into the Write method. Is this StrPut(String, this.pBuf) (length is not specified) Ok or I have to calculate and specify length each time I call StrPut() ?


My Website • Recommended: AutoHotkey Unicode 32-bit • Join DropBox, Copy


HotKeyIt
  • Moderators
  • 7439 posts
  • Last active: Jun 22 2016 09:14 PM
  • Joined: 18 Jun 2008

That is alright because you already checked for size.



Learning one
  • Members
  • 1483 posts
  • Last active: Jan 02 2016 02:30 PM
  • Joined: 04 Apr 2009

Thank you! wink.png

 

[solved]


My Website • Recommended: AutoHotkey Unicode 32-bit • Join DropBox, Copy