API for reading memory

Posted on 1997-06-16
Last Modified: 2006-11-17
I am writing a program that that uses API calls to store a large file in a Allocated Chunk of memory.  How can I retrieve data from this chunk and store it back in to an array.
Question by:stephaner
  • 5
  • 3
  • 3

Expert Comment

ID: 1427313
What is the function you are using to put it in memory?

Author Comment

ID: 1427314
Here is a copy of the subroutine.  This subroutine is part of a class.

Public Sub Load()
  Dim FileSize As Long      'Used to store the file size
  Dim hFile As Long         'Used as a handle to the File
  Dim retval As Long        'Used as generic return value
  Dim lpBytesread As Long   'Used by Api(ReadFile)

  'Get the size of the file
    FileSize = FileLen(FileName)

  'Verify that the file is not zero length.
    If FileSize > 0 Then

      'Allocate a block of memory equal to the size of the input file.
        mlng_HandleMemory = GlobalAlloc(GMEM_ZEROINIT, FileSize)

        'Verify that the allocation succeded
          If mlng_HandleMemory <> 0 Then

            'Lock newly allocated memory
              mlng_MemoryAddress = GlobalLock(mlng_HandleMemory)
            'Open the File
              hFile = CreateFile(FileName, GENERIC_READ, FILE_SHARE_READ, ByVal 0&, OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, ByVal 0&)
            'Read File into Memory
              retval = lread(hFile, ByVal mlng_MemoryAddress, FileSize)
            'Close the File
              retval = CloseHandle(hFile)

Expert Comment

ID: 1427315
Try the following API call:

Declare Function ReadProcessMemory Lib "kernel32" Alias "ReadProcessMemory" (ByVal hProcess As Long, lpBaseAddress As Any, lpBuffer As Any, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long

Here is an explanation of the function:

The ReadProcessMemory function reads memory in a specified process. The entire area to be read must be accessible, or the operation fails.
BOOL ReadProcessMemory(
    HANDLE hProcess,      // handle of the process whose memory is read  
    LPCVOID lpBaseAddress,      // address to start reading
    LPVOID lpBuffer,      // address of buffer to place read data
    DWORD nSize,      // number of bytes to read
    LPDWORD lpNumberOfBytesRead       // address of number of bytes read
Identifies an open handle of a process whose memory is read. The handle must have PROCESS_VM_READ access to the process.
Points to the base address in the specified process to be read. Before any data transfer occurs, the system verifies that all data in the base address and memory of the specified size is accessible for read access. If this is the case, the function proceeds; otherwise, the function fails.
Points to a buffer that receives the contents from the address space of the specified process.
Specifies the requested number of bytes to read from the specified process.
Points to the actual number of bytes transferred into the specified buffer. If lpNumberOfBytesRead is NULL, the parameter is ignored.
Return Values
If the function succeeds, the return value is TRUE.
If the function fails, the return value is FALSE. To get extended error information, call GetLastError.
The function fails if the requested read operation crosses into an area of the process that is inaccessible.
ReadProcessMemory copies the data in the specified address range from the address space of the specified process into the specified buffer of the current process. Any process that has a handle with PROCESS_VM_READ access can call the function. The process whose address space is read is typically, but not necessarily, being debugged.
The entire area to be read must be accessible. If it is not, the function fails as noted previously.

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!


Expert Comment

ID: 1427316
Also note that after you are done with the memory you need to do a GlobalUnlock which I don't see in your above code.

Author Comment

ID: 1427317
I am not sure how to put my class together using this function.  Maybe a little background on what I am trying to achieve would help.
My class is used for bitmap manipulation and display.  The idea is that I would have a load function which copies the whole file into memory.  Then I could implement functions to read and dissect the data such as getting the BitmapHeadears, Bitmapdata, ShowBitmap, SaveBitmap.  It seems that since I will be accessing this data often, it would be faster to do it this way than simply reading the data from the file every time I need it.

It is for this reason that there is no call to unlock the memory as this would be done in the Save routine.

Also I have implemented this save routine, although it does copy data back into a file (using lwrite),  the data does not correspond with the original copy of it.

Is it that my approach to the problem is inadequate, or unrealizable?


Author Comment

ID: 1427318


Accepted Solution

y96andha earned 100 total points
ID: 1427319
Use the RtlMoveMemory function.

Example to copy 400 bytes of data starting with position 20 in the memory chunk, and to put these bytes back at position 1024 in the memory chunk:

Declare Sub MoveMemory1 Lib "kernel32"  Alias "RtlMoveMemory" (Byval dest as String, Byval src as Long, Byval bytes as Long)

Declare Sub MoveMemory2 Lib "kernel32"  Alias "RtlMoveMemory" (Byval dest as Long, Byval src as String, Byval bytes as Long)

Dim data as String
CopyMemory1 data, mlng_MemoryAddress+20, 400

CopyMemory2 mlng_MemoryAddress+1024, data, 400

Please comment if you have any questions.


Author Comment

ID: 1427320
I could not find the above declrations in the API file.  Do you no why?  Also right now I am using "agCopyData" to perform this task. However, this does not allow me to read in anything other than a string.  I would like to be able to read in directly other data types such as Intgers and Longs.  Would your functions allow for this?

Expert Comment

ID: 1427321
Yes, they would. All you have to do is to make sure that the declaration passes pointers as the first two arguments and a length as the last. To read a Long, you would make a declaration like this:

Declare Sub MoveMemory3 Lib "kernel32" Alias "RtlMoveMemory" (dest as Long, Byval src as Long, Byval bytes as Long)

Dim data as Long
MoveMemory3 data, mlng_MemoryAddress+47, Len(data)

Notice that there is no ByVal on the first argument, which makes  VB take its address and pass it to the DLL function.

I do not know why the declaration is not in the API file. Maybe because VB isn't made for using pointers. Do you know if there is any instruction in VB to get the address of a certain variable? Anyway, I got the declaration from my C++ compiler, so it should work.

I cannot find a declaration for agCopyData either.


Author Comment

ID: 1427322
Ok, I was able to make it work for the following types: Byte, String, Integer, Long.  However I still need to know what the declare would be for an array of bytes? a UDT?  Also I had to modify each declare depending on the type.  Is there a way to have only one declare that fits all?

"agCopydata" is part of a lib called "ApiGid32.dll"
This lib contans the functions you mentioned such as:
agGetAddressForObject, gGetAddressForInteger, agGetAddressForLPSTR
and other usefull functions.  For more inforrmation on this lib:

Expert Comment

ID: 1427323
I do not know for an array of bytes. I have a student version of VB, which means I do not have a manual, just a CD. I think that you should pass the first byte. UDT= User Defined Type? In that case, it will work just like Byte, Integer, Long and so on.

To make a declare fit all, you should use

Declare Sub MoveMemory Lib "kernel32" Alias "RtlMoveMemory" (dest as Any, src as Any, Byval bytes as Long)

This should enable you to specify whatever type you'd like. It could be that you still need need to specify the pointer address, that is, the mlng_MemoryAddress part as "ByVal xxx as Long".

On the other hand, if you can get the address for any data type, then you can use

Declare Sub MoveMemory Lib "kernel32" Alias "RtlMoveMemory" (ByVal dest as Long, ByVal src as Long, Byval bytes as Long)

and just pass in the addresses.


Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This article describes some techniques which will make your VBA or Visual Basic Classic code easier to understand and maintain, whether by you, your replacement, or another Experts-Exchange expert.
Since upgrading to Office 2013 or higher installing the Smart Indenter addin will fail. This article will explain how to install it so it will work regardless of the Office version installed.
Show developers how to use a criteria form to limit the data that appears on an Access report. It is a common requirement that users can specify the criteria for a report at runtime. The easiest way to accomplish this is using a criteria form that a…
This lesson covers basic error handling code in Microsoft Excel using VBA. This is the first lesson in a 3-part series that uses code to loop through an Excel spreadsheet in VBA and then fix errors, taking advantage of error handling code. This l…

713 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question