Sign in to follow this  
Followers 0
livewire

Shared Memory via Dll

28 posts in this topic

Here is an example of sharing memory between two AutoIt scripts using a dll. If anyone has any info on how to make the dll better, let me know. Run both scripts at the same time with the dll in the same path to use.

Dll Code:

#include <windows.h>
           #include <memory.h>
           #include <string.h>
           
           #define SHMEMSIZE 4096 
           
           static LPVOID lpvMem = NULL;   // pointer to shared memory
           static HANDLE hMapObject = NULL;  // handle to file mapping
           
           // The DLL entry-point function sets up shared memory using a 
           // named file-mapping object. 
           
           BOOL WINAPI DllMain(HINSTANCE hinstDLL,  // DLL module handle
               DWORD fdwReason,           // reason called 
               LPVOID lpvReserved)         // reserved 
           { 
               BOOL fInit, fIgnore;
               
               switch (fdwReason) 
               { 
                   // DLL load due to process initialization or LoadLibrary
                   case DLL_PROCESS_ATTACH: 
                       // Create a named file mapping object
                       hMapObject = CreateFileMapping( 
                           INVALID_HANDLE_VALUE,   // use paging file
                           NULL,                   // default security attributes
                           PAGE_READWRITE,       // read/write access
                           0,                     // size: high 32-bits
                           SHMEMSIZE,             // size: low 32-bits
                           TEXT("dllmemfilemap")); // name of map object
                       if (hMapObject == NULL) 
                           return FALSE; 
                       // The first process to attach initializes memory
                       fInit = (GetLastError() != ERROR_ALREADY_EXISTS); 
                       
                       // Get a pointer to the file-mapped shared memory
                       lpvMem = MapViewOfFile( 
                           hMapObject,   // object to map view of
                           FILE_MAP_WRITE, // read/write access
                           0,             // high offset:  map from
                           0,             // low offset:   beginning
                           0);           // default: map entire file
                       if(lpvMem == NULL) return FALSE;
                       // Initialize memory if this is the first process
                       if(fInit) memset(lpvMem, '', SHMEMSIZE); 
                       break; 
                   // The attached process creates a new thread
                   case DLL_THREAD_ATTACH: 
                       break; 
                   // The thread of the attached process terminates
                   case DLL_THREAD_DETACH: 
                       break; 
                   // DLL unload due to process termination or FreeLibrary
                   case DLL_PROCESS_DETACH: 
                       // Unmap shared memory from the process's address space
                       fIgnore = UnmapViewOfFile(lpvMem); 
                       // Close the process's handle to the file-mapping object
                       fIgnore = CloseHandle(hMapObject); 
                       break; 
                   default: 
                       break; 
                } 
               return TRUE; 
               UNREFERENCED_PARAMETER(hinstDLL); 
               UNREFERENCED_PARAMETER(lpvReserved); 
           }
            
           // SetSharedMem sets the contents of the shared memory 
           VOID _stdcall SetSharedMem(char *str) 
           {
               char *lpszTmp;
           
               // Get the address of the shared memory block
               lpszTmp = (char *) lpvMem;
               strncpy(lpszTmp,str,SHMEMSIZE);
           } 
            
           // GetSharedMem gets the contents of the shared memory
           VOID _stdcall GetSharedMem(char *str, int size) 
           {
               char *lpszTmp;
           
               // Get the address of the shared memory block
               lpszTmp = (char *) lpvMem;
               strncpy(str,lpszTmp,size);
           }

1st Script:

#include <GUIConstants.au3>
        
        Dim $dll
        Dim $ret
        Dim $read_string = ""
        
        $dll = DllOpen("SharedMemory.dll")
        If @error Then
            MsgBox(0,"Testing","Error opening dll")
        EndIf
        
        $Form1 = GUICreate("Test1", 360, 321, 280, 230)
        $Button1 = GUICtrlCreateButton("SetSharedMem", 40, 40, 81, 25, 0)
        $Button2 = GUICtrlCreateButton("GetSharedMem", 43, 70, 81, 25, 0)
        $Input1 = GUICtrlCreateInput("", 144, 40, 153, 21)
        $Input2 = GUICtrlCreateInput("", 144, 72, 153, 21)
        GUISetState(@SW_SHOW)
        
        While 1
            $nMsg = GUIGetMsg()
            Switch $nMsg
                Case $Button1
                    DllCall($dll,"none","SetSharedMem","str",GUICtrlRead($Input1))
                    If @error Then
                        MsgBox(0,"Testing","Error calling SetSharedMem")
                        Exit
                    EndIf
                Case $Button2
                    $ret = DllCall($dll,"none","GetSharedMem","str",$read_string,"int",50)
                    If @error Then
                        MsgBox(0,"Testing","Error calling GetSharedMem")
                        Exit
                    Else
                        GUICtrlSetData($Input2,$ret[1])
                    EndIf
                Case $GUI_EVENT_CLOSE
                    Exit
            EndSwitch
        WEnd
        
        DllClose($dll)
        If @error Then
            MsgBox(0,"Testing","Error closing dll")
        EndIf

SharedMemory.zip

Share this post


Link to post
Share on other sites



Nice. Simple and pretty :)

CreateFileMapping( 
                           INVALID_HANDLE_VALUE,
                           // ...

Question: why do you want to explicitly use swap? I mean, using physical memory would be faster... And now, everytime the memory is accessed, a paging fault occurs and the system moves the data from pagefile.sys (or whatever) to physical RAM... :/

Anyway, I like the simplicity ;)

Share this post


Link to post
Share on other sites

Here is an example of sharing memory between two AutoIt scripts using a dll. If anyone has any info on how to make the dll better, let me know. Run both scripts at the same time with the dll in the same path to use.

That works well and it is a different approach to anything I have tried so far.

I have only just started trying to use memory and I understand very little so I can't make any useful comments about your dll, but I have some questions.

1. Do you think you could have done the same with the available memory udf's, and if not why not?

2. Can you tell me the advantages of the way you have done it compared to the example I gave in the 'Data Interchange between scripts' thread. (here)

3. I find it a bit slow going understanding the memory functions. Can you give any links for an idiot's guide to memory usage? I don't understand memory maps (or rather I know what a memory map is but not the way memory is organised, allocated, used etc), access rights, you name it.


Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script.

Share this post


Link to post
Share on other sites

That works well and it is a different approach to anything I have tried so far.

I have only just started trying to use memory and I understand very little so I can't make any useful comments about your dll, but I have some questions.

1. Do you think you could have done the same with the available memory udf's, and if not why not?

2. Can you tell me the advantages of the way you have done it compared to the example I gave in the 'Data Interchange between scripts' thread. (here)

3. I find it a bit slow going understanding the memory functions. Can you give any links for an idiot's guide to memory usage? I don't understand memory maps (or rather I know what a memory map is but not the way memory is organised, allocated, used etc), access rights, you name it.

I found this code on codeproject and changed it to work with AutoIt.

1. I haven't used the memory udfs. But in the quick glance that I looked at it, I'm sure you could do the same.

Sorry, I can't answer those complicated memory questions. I was hoping someone could just change the code if it's possible to: not use swap, not use dll, etc.

Share this post


Link to post
Share on other sites

#5 ·  Posted (edited)

Hi, Livewire!

You are FANTASTIC!!!

Your Script/Method/DLL is compatible with the mmap module/methods of Python (programming language).

And, like the memmap library, in Ruby, is compatible with Python, I think that your work is also compatible with Ruby.

If you want... just an enhancement : the possibity to choose/drive the name of the mapping (change "dllmemfilemap" to parameter)

EDIT: and also, put the size of buffer (actually 4096) like parameter

(and ***sorry for my bad english***)

Edited by Michel Claveau

Share this post


Link to post
Share on other sites

#6 ·  Posted (edited)

Re, Livewire;

Please... Which C compiler had you use, for create the DLL?

I had try with TCC, but the DLL don't run (and I don't know C)

Edited by Michel Claveau

Share this post


Link to post
Share on other sites

Try GNU's g++, it's open source (default in Code::Blocks and Dev-Cpp IDE).

An alternative would be Microsoft Visual C++ or Microsoft Visual Studio. I suppose Visual Studio is the best choice when programming Windows applications.

Share this post


Link to post
Share on other sites

#8 ·  Posted (edited)

Hi!

Thank you, Zatorg !

I have MinGW (because I test Pyrex).

I had can compile a DLL. But I don't know C, then I don't know how to make a function for put "name" & "size" like parameters.

But, I change the buffer size to 32767, and the name to "autoitmmap" (this name is not used in the Livewire's exemple)

Also, I had renamed the DLL to autoitmmap.dll (for no confuse with livewire's work)

For compile, I found that :

create the file autoitmmap.def (who contain the exports names of functions)

gcc -c -I"D:\dev\MinGW\include" -enable-stdcall-fixup -o autoitmmap.o autoitmmap.c

gcc -shared -I"D:\dev\MinGW\include" -enable-stdcall-fixup -o autoitmmap.dll autoitmmap.c autoitmmap.def

The result is a file, with a little size. This file run with Livewire's exemple (only change the name of DLL)

And, a source code, in Python, for exchange data with AutoIt :

import mmap

data='Qwerty1234567890'

# write data
objmmap=mmap.mmap(0,32767,'autoitmmap')
objmmap.seek(0)
objmmap.write(data)
objmmap.flush()

raw_input('write Ok; [Enter] for read')

#read data
objmmap.seek(0)
receiv=objmmap.read(32767)
print len(receiv),receiv

#objmmap.close()   #option

I give the DLL in attachment.

autoitmmap.dll

Edited by Michel Claveau

Share this post


Link to post
Share on other sites

Nice. Simple and pretty :)

CreateFileMapping( 
                           INVALID_HANDLE_VALUE,
                           // ...

Question: why do you want to explicitly use swap? I mean, using physical memory would be faster... And now, everytime the memory is accessed, a paging fault occurs and the system moves the data from pagefile.sys (or whatever) to physical RAM... :/

Anyway, I like the simplicity ;)

What is needed to use physical memory? I assume I would need AWE but I don't know how to set that up in XP home so if you can advise I would be very pleased.

Can you answer any of my questions in post #3?


Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script.

Share this post


Link to post
Share on other sites

Hi, Livewire!

You are FANTASTIC!!!

Your Script/Method/DLL is compatible with the mmap module/methods of Python (programming language).

And, like the memmap library, in Ruby, is compatible with Python, I think that your work is also compatible with Ruby.

If you want... just an enhancement : the possibity to choose/drive the name of the mapping (change "dllmemfilemap" to parameter)

EDIT: and also, put the size of buffer (actually 4096) like parameter

(and ***sorry for my bad english***)

Sounds good...will try to do that.

Re, Livewire;

Please... Which C compiler had you use, for create the DLL?

I had try with TCC, but the DLL don't run (and I don't know C)

Microsoft Visual C++ 6.0, but should be able to get it to compile using 2005 or devC++.

-Livewire

Share this post


Link to post
Share on other sites

#11 ·  Posted (edited)

Hi!

Livewire, your C-source-code, give a 200 kB DLL with MS-VC++, but give a 15 kB with MinGW...

Finding: for your next release, keep yet to give the source. Thanks by advance.

Edited by Michel Claveau

Share this post


Link to post
Share on other sites

is it faster than RamDisk technique to share variables between processes ?

Share this post


Link to post
Share on other sites

is it faster than RamDisk technique to share variables between processes ?

How do you make a RAMDISK?

The best way to see if it's faster or not is to try some tests.


Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script.

Share this post


Link to post
Share on other sites

Hi, Mary!

is it faster than RamDisk technique to share variables between processes ?

Yes, it's faster. But it's less powerful and less easy.

Because a RAMDisk manage all the files-system, contrary to the technique used here.

Share this post


Link to post
Share on other sites

(Have been away for some time..)

What is needed to use physical memory?

Physical memory is the memory in RAM disks. When an OS runs out of physical RAM, it uses virtual memory (setting up VM). Windows allocates a paging file (PF, typically pagefile.sys) on the hard disk to use it instead of physical RAM when running low on free physical memory.

So when one isn't using physical memory ("real" RAM) then he/she is using virtual memory which is on a hard disk thus much slower to read/write to.

(Actually, to be accurate virtual memory is physical memory plus "swap" (paging/swap files))

Anyway, sorry for the ignorance, too lazy and haven't got much time.

Share this post


Link to post
Share on other sites

(Have been away for some time..)

Physical memory is the memory in RAM disks. When an OS runs out of physical RAM, it uses virtual memory (setting up VM). Windows allocates a paging file (PF, typically pagefile.sys) on the hard disk to use it instead of physical RAM when running low on free physical memory.

So when one isn't using physical memory ("real" RAM) then he/she is using virtual memory which is on a hard disk thus much slower to read/write to.

(Actually, to be accurate virtual memory is physical memory plus "swap" (paging/swap files))

Anyway, sorry for the ignorance, too lazy and haven't got much time.

Just a follow up on the memory used by the dll. It looks to me like the dll uses physical memory which is the default for the CreateFileMapping API, and the INVALID_HANDLE_VALUE isn't related to that, but to whether the memory map is defined in a file or not. Info from here.

It also looks to me like the dll could be replaced by AutoIt code since it appears to be based on calls to kernel32.dll.

One of the things I don't know is what are the benefits, if any, of using allocating memory like this compared to memory used by a DllStructCreate, and then read by another process. Can anyone can enlighten me?


Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script.

Share this post


Link to post
Share on other sites

#17 ·  Posted (edited)

HANDLE WINAPI CreateFileMapping(
  HANDLE [i]hFile[/i],

Darn! CreateFileMapping() always allocates memory on a physical hard disk, not in physical memory :)

This means that DllStructCreate() / memory allocation at runtime should (only thought, no experience) be faster than CreateFileMapping().

Although CreateFileMapping() is intended for shared memory access etc. and DllStructCreate() is not, DllStructCreate() may allocate memory pages in physical memory whereas CreateFileMapping (darn I'm stupid) allocates memory on a paging file.

hFile [in] A handle to the file from which to create a file mapping object.

If hFile is INVALID_HANDLE_VALUE, the calling process must also specify a size for the file mapping object [...] In this scenario, CreateFileMapping creates a file mapping object of a specified size that is backed by the system paging file instead of by a file in the file system.

=> Either way, memory is allocated on the hard disk, not in the real (physical) RAM.

Edit: some mistakes..

Edited by zatorg

Share this post


Link to post
Share on other sites

#18 ·  Posted (edited)

And yes you're right, like I said (or haven't I? Amnesia :) ) this could be done in AutoIt3..

Anyway:

  • If one is using small variables and he/she needs to share them between processes, CreateFileMapping() is easy and efficient.
  • If one wants to share large memory regions, I suggest he/she using memory allocation the "normal" way (malloc(), or DllStructCreate() in AutoIt), and then accessing that memory from another process..
Just a thought.. Edited by zatorg

Share this post


Link to post
Share on other sites

#19 ·  Posted (edited)

And yes you're right, like I said (or haven't I? Amnesia :) ) this could be done in AutoIt3..

Anyway:

  • If one is using small variables and he/she needs to share them between processes, CreateFileMapping() is easy and efficient.
  • If one wants to share large memory regions, I suggest he/she using memory allocation the "normal" way (malloc(), or DllStructCreate() in AutoIt), and then accessing that memory from another process..
Just a thought..

at now, we can't share a variable (DllStructCreate) between 2 autoit scripts !

maybe, only throw an external dll but not directly between 2 autoit script

Edited by mary

Share this post


Link to post
Share on other sites

#20 ·  Posted (edited)

Hi!

at now, we can't share a variable (DllStructCreate) between 2 autoit scripts !

Share variable: no!

But exchange data: yes. And exchange data to/from autoit script and other autoit scripts, Python scripts, or Ruby scripts.

More exactly, the goal is to share a memory area, and putting/getting data into.

Edited by Michel Claveau

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0