Lazarus

Programming => Operating Systems => Windows => Topic started by: LazUser20 on May 13, 2021, 10:46:27 pm

Title: How do I give a Pointer to a other process
Post by: LazUser20 on May 13, 2021, 10:46:27 pm
I have the following data structure.

Code: Pascal  [Select][+][-]
  1. type
  2.   PRasterImageInfo=^TRasterImageInfo;
  3.   TRasterImageInfo=packed record
  4.     nSize: DWord;
  5.     nItemID: LongInt;
  6.     hItem: THandle;
  7.     nFlags, nWidth, nHeight, nResSize: DWord;
  8.   end;
  9.  


It is filled with data:

Code: Pascal  [Select][+][-]
  1. procedure TForm1.BitBtn1Click(Sender: TObject);
  2. begin
  3.   if OpenPictureDialog1.Execute
  4.     then
  5.       begin
  6.         Image1.Picture.LoadFromFile(OpenPictureDialog1.FileName);
  7.  
  8.         RasterImageInfo.nSize:=sizeOf(RasterImageInfo);
  9.         RasterImageInfo.nItemID := 1;
  10.         RasterImageInfo.hItem := Image1.Picture.Bitmap.Handle;
  11.         RasterImageInfo.nFlags := $0007;
  12.         RasterImageInfo.nWidth  := Image1.Picture.Bitmap.Width;
  13.         RasterImageInfo.nHeight := Image1.Picture.Bitmap.Height;
  14.         RasterImageInfo.nResSize := GetFileSize(OpenPictureDialog1.FileName);
  15.  
  16.         ValueListEditor1.Values['nSize']:=IntToStr(RasterImageInfo.nSize);
  17.         ValueListEditor1.Values['nItemID']:=IntToStr(RasterImageInfo.nItemID);
  18.         ValueListEditor1.Values['nItem']:=IntToStr(RasterImageInfo.nItemID);
  19.         ValueListEditor1.Values['nFlags']:=IntToStr(RasterImageInfo.nFlags);
  20.         ValueListEditor1.Values['nWidth']:=IntToStr(RasterImageInfo.nWidth);
  21.         ValueListEditor1.Values['nHeight']:=IntToStr(RasterImageInfo.nHeight);
  22.         ValueListEditor1.Values['nResSize']:=IntToStr(RasterImageInfo.nResSize);
  23.         Label1.Caption := IntToStr(Image1.Picture.Bitmap.Width*Image1.Picture.Bitmap.Height*24);
  24.  
  25.       end;
  26. end;        
  27.  

How do I send the pointer to a other process (maybe as start parameter), to access the data of this structure in the other process?

The data structure is from here: http://www.x-ways.net/forensics/x-tensions/XWF_functions.html#E

At this time the second process read the pointer from the start arguments:

Code: C  [Select][+][-]
  1. #include <iostream> // std::cout, std::endl, std::cin
  2. #include <windows.h>
  3. #include <X-Tension.h>
  4. #include <stdlib.h> // EXIT_SUCCESS
  5. #include <string.h> // strcmp()
  6.  
  7. int main(int argc, struct RasterImageInfo* pRIInfo)
  8. {
  9.         for (int i = 0; i < argc; i++)
  10.         {
  11.                 // Ausgabe aller Parameter
  12.                 std::cout << i << " \"" << pRIInfo->nSize<< "\"" << std::endl;
  13.         std::cout << i << " \"" << pRIInfo->nItemID << "\"" << std::endl;
  14.         std::cout << i << " \"" << pRIInfo->hItem << "\"" << std::endl;
  15.         std::cout << i << " \"" << pRIInfo->nFlags << "\"" << std::endl;
  16.         std::cout << i << " \"" << pRIInfo->nWidth << "\"" << std::endl;
  17.         std::cout << i << " \"" << pRIInfo->nHeight << "\"" << std::endl;
  18.         std::cout << i << " \"" << pRIInfo->nResSize << "\"" << std::endl;
  19.         }
  20.  
  21.         std::cin.get();
  22.         return EXIT_SUCCESS;
  23. }
  24.  
  25.  

The pascal program is only for testing, if the C++-Tool read valid data, because I dont have access to a X-Ways.
Title: Re: How do I give a Pointer to a other process
Post by: ASerge on May 14, 2021, 02:38:09 am
Passing pointers is useless until a copy of the memory is passed, because Windows processes each have their own memory. There are several memory sharing mechanisms, but this must be explicitly implemented in both processes. Are you the creator of programs for both processes?
Title: Re: How do I give a Pointer to a other process
Post by: Remy Lebeau on May 14, 2021, 03:28:11 am
How do I send the pointer to a other process (maybe as start parameter), to access the data of this structure in the other process?

You can't use pointers across process boundaries.  What you can do instead is allocate a named block of shared memory via CreateFileMapping() (https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-createfilemappingw) and MapViewOfFile() (https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-mapviewoffile) (see Sharing Files and Memory (https://docs.microsoft.com/en-us/windows/win32/memory/sharing-files-and-memory)), and then each process can obtain its own pointer to the shared memory and read/write data in the block as needed.  You could pass the file mapping's shared name in a command-line parameter, if needed.

Note: you can't share an HBITMAP handle across processes, period.  So this approach will not work for sharing the TRasterImageInfo.hItem field.  You will have to save the TBitmap's pixel data according to MSDN's Bitmap Storage (https://docs.microsoft.com/en-us/windows/win32/gdi/bitmap-storage) documentation.  For instance, by saving the TBitmap to a TMemoryStream and then copying the raw bytes from the stream to the shared memory.

For example:

Code: Pascal  [Select][+][-]
  1. type
  2.   PRasterImageInfo = ^TRasterImageInfo;
  3.   TRasterImageInfo = packed record
  4.     nSize: DWord;
  5.     nItemID: LongInt;
  6.     nFlags, nWidth, nHeight, nResSize: DWord;
  7.     nResBytes: array[0..0] of Byte;
  8.   end;
  9.      
  10. procedure TForm1.BitBtn1Click(Sender: TObject);
  11. var
  12.   MemStrm: TMemoryStream;
  13.   MemSize: DWORD;
  14.   hMapping: THandle;
  15.   RasterImageInfo: PRasterImageInfo;
  16. begin
  17.   if OpenPictureDialog1.Execute then
  18.   begin
  19.     Image1.Picture.LoadFromFile(OpenPictureDialog1.FileName);
  20.      
  21.     MemStrm := TMemoryStream.Create;
  22.     try
  23.       Image1.Picture.Bitmap.SaveToStream(MemStrm);
  24.       MemSize := (SizeOf(TRasterImageInfo) - 1) + MemStrm.Size;
  25.  
  26.       hMapping := CreateFileMapping(INVALID_HANDLE_VALUE, nil, PAGE_READWRITE, 0, MemSize, 'RasterImageInfo');
  27.       if hMapping = 0 then RaiseLastOSError;
  28.       try
  29.         RasterImageInfo := MapViewOfFile(hMapping, FILE_MAP_WRITE, 0, 0, MemSize);
  30.         if RasterImageInfo = nil then RaiseLastOSError;
  31.         try
  32.           RasterImageInfo.nSize := MemSize;
  33.           RasterImageInfo.nItemID := 1;
  34.           RasterImageInfo.nFlags := $0007;
  35.           RasterImageInfo.nWidth  := Image1.Picture.Bitmap.Width;
  36.           RasterImageInfo.nHeight := Image1.Picture.Bitmap.Height;
  37.           RasterImageInfo.nResSize := Strm.Size;
  38.           Move(MemSStrm.Memory^, RasterImageInfo.nResBytes[0], Strm.Size);
  39.  
  40.           // run external program, wait for it to finish using RasterImageInfo ...
  41.  
  42.       finally
  43.         UnmapViewOfFile(RasterImageInfo);
  44.       end;
  45.     finally
  46.       CloseHandle(hMapping);
  47.     end;
  48.   finally
  49.     MemStrm.Free;
  50.   end;
  51. end;

Code: C  [Select][+][-]
  1. #include <iostream> // std::cout, std::endl, std::cin
  2. #include <windows.h>
  3. #include <X-Tension.h>
  4. #include <cstdlib> // EXIT_SUCCESS
  5. #include <cstring> // std::strcmp()
  6.  
  7. #pragma pack(push, 1) // <-- or your compiler's equivalent
  8. typedef struct TRasterImageInfo
  9. {
  10.     DWORD nSize;
  11.     LONG nItemID;
  12.     DWORD nFlags, nWidth, nHeight, nResSize;
  13.     BYTE nResBytes[1];
  14. } TRasterImageInfo, *PRasterImageInfo;
  15. #pragma pack(pop) // <-- or your compiler's equivalent
  16.      
  17. int main(int argc, char* argv[])
  18. {    
  19.     HANDLE hMapping = OpenFileMapping(FILE_MAP_READ, FALSE, TEXT("RasterImageInfo"));
  20.     if (hMapping == NULL)
  21.         return EXIT_FAILURE;
  22.  
  23.     PRasterImageInfo pRIInfo = (PRasterImageInfo) MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0);
  24.     if (pRIInfo == NULL)
  25.     {
  26.         CloseHandle(hMapping);
  27.         return EXIT_FAILURE;
  28.     }
  29.  
  30.     // Ausgabe aller Parameter
  31.     std::cout << i << " \"" << pRIInfo->nSize << "\"" << std::endl;
  32.     std::cout << i << " \"" << pRIInfo->nItemID << "\"" << std::endl;
  33.     std::cout << i << " \"" << pRIInfo->nFlags << "\"" << std::endl;
  34.     std::cout << i << " \"" << pRIInfo->nWidth << "\"" << std::endl;
  35.     std::cout << i << " \"" << pRIInfo->nHeight << "\"" << std::endl;
  36.     std::cout << i << " \"" << pRIInfo->nResSize << "\"" << std::endl;
  37.     // use pRIInfo->nResBytes as needed...
  38.  
  39.     UnmapViewOfFile(pRIInfo);
  40.     CloseHandle(hMapping);
  41.  
  42.     std::cin.get();
  43.     return EXIT_SUCCESS;
  44. }
Title: Re: How do I give a Pointer to a other process
Post by: LazUser20 on May 30, 2021, 02:21:42 pm
OK. Thank you for your help.

How do I put the whole record at the process execute (or something similar) to get it as process parameter at the other programm?

Is ist possible just to get only a FilePointer and put this in a record instead of a handle to memory?
Title: Re: How do I give a Pointer to a other process
Post by: MarkMLl on May 30, 2021, 02:53:31 pm
OK. Thank you for your help.

How do I put the whole record at the process execute (or something similar) to get it as process parameter at the other programm?

Use shared memory.

Quote
Is ist possible just to get only a FilePointer and put this in a record instead of a handle to memory?

In general, no. You can pass a filename around and then open that with appropriate locking discipline, but you might do better considering IPC using OS-specific or UDP datagrams.

MarkMLl
Title: Re: How do I give a Pointer to a other process
Post by: engkin on May 30, 2021, 03:03:51 pm
X-Ways expects your code to be in a DLL. Meaning your code is going to be in the "same" process.
Title: Re: How do I give a Pointer to a other process
Post by: Remy Lebeau on May 31, 2021, 11:17:19 am
How do I put the whole record at the process execute (or something similar) to get it as process parameter at the other programm?

Copy the record into shared memory, exactly like how I showed you. Did you even try it?

Is ist possible just to get only a FilePointer and put this in a record instead of a handle to memory?

No.
Title: Re: How do I give a Pointer to a other process
Post by: LazUser20 on June 09, 2021, 07:20:04 pm
X-Ways expects your code to be in a DLL. Meaning your code is going to be in the "same" process.

Actual I don't have Xways so at this time it is not planed to build a X-tension. The project only should address the processing of the data and this maybe will be used later for building an xtension. 
So I plan to build a tool, which read an image file and create the data structure and give this to the c++ program.
Title: Re: How do I give a Pointer to a other process
Post by: ccrause on June 09, 2021, 09:36:16 pm
X-Ways expects your code to be in a DLL. Meaning your code is going to be in the "same" process.

Actual I don't have Xways so at this time it is not planed to build a X-tension. The project only should address the processing of the data and this maybe will be used later for building an xtension. 
So I plan to build a tool, which read an image file and create the data structure and give this to the c++ program.
Do you have an example of calling this C++ program with a pointer to RasterImageInfo?  I only know the very basics of C/C++, but the main function of the C++ program you showed in the first post looks non-standard.  Is that a real working program?
Title: Re: How do I give a Pointer to a other process
Post by: LazUser20 on June 13, 2021, 04:51:42 pm

Copy the record into shared memory, exactly like how I showed you. Did you even try it?


Yes I tryed, but the compiler didn't compiled the Lazarus Part.

At "RasterImageInfo.nSize := MemSize;" there are errors:

Error: Illegal qualifier
Hint: may be pointer dereference is missing
Error: Illegal expression

I could fix it to this:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.BitBtn1Click(Sender: TObject);
  2.  
  3. var
  4.   MemStrm: TMemoryStream;
  5.   MemSize: DWORD;
  6.   hMapping: THandle;
  7.   RasterImageInfo: PRasterImageInfo;
  8.   Output: String;
  9. begin
  10.   if OpenPictureDialog1.Execute then
  11.   begin
  12.     Image1.Picture.LoadFromFile(OpenPictureDialog1.FileName);
  13.  
  14.     MemStrm := TMemoryStream.Create;
  15.     try
  16.       Image1.Picture.Bitmap.SaveToStream(MemStrm);
  17.       MemSize := (SizeOf(TRasterImageInfo) - 1) + MemStrm.Size;
  18.  
  19.       hMapping := CreateFileMapping(INVALID_HANDLE_VALUE, nil, PAGE_READWRITE, 0, MemSize, 'RasterImageInfo');
  20.       if hMapping = 0 then RaiseLastOSError;
  21.       try
  22.         RasterImageInfo := MapViewOfFile(hMapping, FILE_MAP_WRITE, 0, 0, MemSize);
  23.         if RasterImageInfo = nil then RaiseLastOSError;
  24.         try
  25.           RasterImageInfo^.nSize := MemSize;
  26.           RasterImageInfo^.nItemID := 1;
  27.           RasterImageInfo^.nFlags := $0007;
  28.           RasterImageInfo^.nWidth  := Image1.Picture.Bitmap.Width;
  29.           RasterImageInfo^.nHeight := Image1.Picture.Bitmap.Height;
  30.           RasterImageInfo^.nResSize := MemStrm.Size;
  31.           Move(MemStrm.Memory^, RasterImageInfo^.nResBytes[0], MemStrm.Size);
  32.  
  33.           // run external program, wait for it to finish using RasterImageInfo ...
  34.  
  35.           RunCommand(toolpath, output);
  36.         finally
  37.         end;
  38.       finally
  39.         UnmapViewOfFile(RasterImageInfo);
  40.       end;
  41.     finally
  42.       CloseHandle(hMapping);
  43.       MemStrm.Free;
  44.     end;
  45.   end;
  46. end;      
  47.  
  48.  

Both tools are copiled now.

Is there a simple way to get the picture from the memory drawed at a screen or write it to a file?
So that I can see that it really works?

Update:

I was able to save the File with just this to lines:
Code: C  [Select][+][-]
  1.     #pragma warning(suppress : 4996)
  2.     FILE* file = fopen("memory.bmp", "wb");
  3.     fwrite(pRIInfo->nResBytes, 1, pRIInfo->nResSize, file);
  4.  

The size and the md5 hash are equal to the orignal file, if that was a normal bitmap image.
This is a good basis for further working.

Big Thanks to Remy Lebeau

Title: Re: How do I give a Pointer to a other process
Post by: Remy Lebeau on June 13, 2021, 09:03:20 pm
Yes I tryed, but the compiler didn't compiled the Lazarus Part.

At "RasterImageInfo.nSize := MemSize;" there are errors:

Error: Illegal qualifier
Hint: may be pointer dereference is missing
Error: Illegal expression

I guess that means FreePascal does not support the same "extended pointer syntax" (http://docwiki.embarcadero.com/RADStudio/en/Pointers_and_Pointer_Types_(Delphi)#Using_Extended_Syntax_with_Pointers) that Delphi does, which allows for omiting the caret (^) when dereferencing a pointer.

I could fix it to this:

That looks correct, yes.
Title: Re: How do I give a Pointer to a other process
Post by: marcov on June 13, 2021, 10:01:14 pm

I guess that means FreePascal does not support the same "extended pointer syntax" (http://docwiki.embarcadero.com/RADStudio/en/Pointers_and_Pointer_Types_(Delphi)#Using_Extended_Syntax_with_Pointers) that Delphi does, which allows for omiting the caret (^) when dereferencing a pointer.

It does for 20 years now. IF you actually set it to Delphi compatibility.
Title: Re: How do I give a Pointer to a other process
Post by: engkin on June 13, 2021, 10:31:37 pm
or use:
Code: Pascal  [Select][+][-]
  1. {$mode objfpc}{$H+}
  2. {$ModeSwitch autoderef}
Title: Re: How do I give a Pointer to a other process
Post by: dsiders on June 13, 2021, 10:40:29 pm
or use:
Code: Pascal  [Select][+][-]
  1. {$mode objfpc}{$H+}
  2. {$ModeSwitch autoderef}

Aha! I've never noticed that one.
Thanks @engkin.
TinyPortal © 2005-2018