How to send a bitmap and text data thought processes using file mapping?

235 Views Asked by At

Im trying to send a bitmap and some text string from a script to another using file mapping, below is my attempt:

FM := new FileMapping()
Return

F1:: FM.Read()
Esc::ExitApp

F2:: ; Write the pbitmap to map

; GDIp startup
VarSetCapacity(si, 8 + A_PtrSize*2, 0), si := Chr(1)
DllCall("gdiplus\GdiplusStartup", "UPtrP", pToken, "Ptr", &si, "Ptr", 0)
; ------------------------------------------------------------------------

; Create the pBitmap #1
File := "test.png"
DllCall("gdiplus\GdipCreateBitmapFromFile", "WStr", File, "PtrP", pBitmap)
; ------------------------------------------------------------------------

; LockBits #2
DllCall("gdiplus\GdipGetImageDimension", Ptr, pBitmap, "float*", width, "float*", height)
DllCall("gdiplus\GdipGetImagePixelFormat", "Ptr", pBitmap, "PtrP", pixelFormat)

VarSetCapacity(Rect, 16)
NumPut(0, Rect, 0, "UInt")
NumPut(0, Rect, 4, "UInt")
NumPut(width, Rect, 8, "UInt")
NumPut(height, Rect, 12, "UInt")

VarSetCapacity(BitmapData, 16+2*(A_PtrSize ? A_PtrSize : 4), 0)
E := DllCall("Gdiplus\GdipBitmapLockBits", "Ptr", pBitmap, "Ptr", &Rect, "UInt", LockMode:=3, "Int", PixelFormat, "Ptr", &BitmapData)
Stride := NumGet(BitmapData, 8, "Int")
Scan0  := NumGet(BitmapData, 16)
size := stride * height
; ------------------------------------------------------------------------


; Append a string into the data 
; that will be saved on memory #3
str  := "test test"
      
VarSetCapacity(data, dataSize := size + 16 + StrLen(str)*2 + 2, 0)
StrPut(str, &data + size + 16)

; Copty the data to memory #4
DllCall("RtlCopyMemory", "Ptr", &data + 16, "Ptr", scan0, "Ptr", size)

DllCall("Gdiplus\GdipBitmapUnlockBits", "UPtr", pBitmap, "UPtr", &BitmapData) 

; ------------------------------------------------------------------------


; Write to map #5
NumPut(pixelFormat, data)
NumPut(width      , data, 4)
NumPut(height     , data, 8)
NumPut(stride     , data, 12, "UInt")

VarSetCapacity(COPYDATASTRUCT, A_PtrSize*3, 0)
NumPut(dataSize, COPYDATASTRUCT, A_PtrSize)
NumPut(&data, COPYDATASTRUCT, A_PtrSize*2)

FM.Write(&COPYDATASTRUCT)
; ------------------------------------------------------------------------

Return



Class FileMapping {
   
   __New(Name="Global\MyFileMappingObject", BufSize=100000) {    
      
      ; 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(data:="") {       
      NumPut(data, this.pBuf)
   }



   Read() {

      static flags := HEAP_ZERO_MEMORY := 0x00000008
         , hHeap := DllCall("GetProcessHeap", "Ptr")

      param := NumGet(this.pBuf)
      size  := NumGet(param + A_PtrSize, "UInt")
      pData := NumGet(param + A_PtrSize*2)

      pHeap := DllCall("HeapAlloc", "Ptr", hHeap, "UInt", flags, "UPtr", size, "Ptr")
      DllCall("RtlCopyMemory", "Ptr", pHeap, "Ptr", pData, "Ptr", size)

      this.CreateBitmapFromData(hHeap, pHeap)
      return

   }



   CreateBitmapFromData(hHeap, pImageData) {

      pixelFormat := NumGet(pImageData+0, "UInt")
      width       := NumGet(pImageData+4, "UInt")
      height      := NumGet(pImageData+8, "UInt")
      stride      := NumGet(pImageData+12,"UInt")
      ; The string appended in the step #3 ("test test")
      str         := StrGet(pImageData + 16 + stride*height)


      
      DllCall("gdiplus\GdipCreateBitmapFromScan0", "Int", width, "Int", height, "Int", stride, "Int", pixelFormat, "Ptr", pImageData + 16, "PtrP", pBitmap)

      DllCall("gdiplus\GdipCreateHBITMAPFromBitmap", "Ptr", pBitmap, "PtrP", hbm, "Int", 0xffffffff)

      ; Just for test, create a gui showing the picture.
      Gui, Add, Picture, x0 y0, % "HBITMAP:" hbm
      Gui, Show

      DllCall("HeapFree", "Ptr", hHeap, "UInt", 0, "Ptr", pImageData)
      DllCall("gdiplus\GdipDisposeImage", "Ptr", pBitmap)

   }



   __Delete() {
      DllCall("UnmapViewOfFile", "Ptr", this.pBuf), DllCall("CloseHandle", "Ptr", this.hMapFile)
   }

}

To write the bitmap and text to the filemap you hit F2

it will create a bitmap(#1) from the given file

call lockbits(#2) on the bitmap, save the scan and a string (#3) into data and copy the data to memory (#4) utilizing RtlCopyMemory

then, save data into the filemap (#5)

When you hit F1 it will call the function Read() from the Class FileMap and will 'rebuild' the bitmap (CreateBitmapFromData) that has been save inside of the filemap, and also read the string appended in step #3

Things works as described as long its read/written from the same script, if i launch a different process and call FM.Read() it doesnt work, the values of size and pData inside of the function Read() are blank:

  param := NumGet(this.pBuf)
  size  := NumGet(param + A_PtrSize, "UInt")
  pData := NumGet(param + A_PtrSize*2)

Appreciate any help on this!

1

There are 1 best solutions below

0
On

You have to add some more error handling. Check all return values and call

DllCall("GetLastError") 

after functions which do not return error codes. That will tell much about what's going on. Without that, it would be difficult to give a complete answer as there are many things that can go wrong.

Use one of the AutoHotkey debugger extensions for VS Code like this one: AutoHotkey Plus