News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

GobalAlloc --> Edit Control

Started by Mark Jones, March 09, 2005, 04:34:14 AM

Previous topic - Next topic

Mark Jones

Hi, is it common or even possible to "lie" and pass a GlobalAlloc pointer as a string to an edit control? I'm trying to load a tiny text file into an edit control and everything works right up to the actual call to SetDlgItemText, where it crashes. It will display the string if it is not buffered in a GlobalAlloc.


Invoke CreateFile, Addr ofnBuffer, GENERIC_READ, FILE_SHARE_READ, \ ; open file
0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 ; handle in eax
Mov hOpenFile, Eax
Invoke GetFileSize, Eax, NULL ; get size
Inc Eax ; add a null
Mov intOpenFileSize, Eax ; save
Invoke GlobalAlloc, GPTR, Eax ; allocate sizeof file + 1
Mov hOpenGlobalAlloc, Eax ; save GlobalAlloc handle
Invoke ReadFile, hOpenFile, Addr hOpenGlobalAlloc,\ ; read file into ram
DWord Ptr intOpenFileSize, Addr intNumBytesRead, 0

; * either of these will cause GPF
Invoke MessageBox, hWnd, Addr hOpenGlobalAlloc, Addr ofnBuffer, MB_OK
Invoke SetDlgItemText, hWnd, IDC_TSC_EDIT1, Addr hOpenGlobalAlloc

Invoke CloseHandle, hOpenFile ; close file
Invoke GlobalFree, hOpenGlobalAlloc ; free memory


Looking at the contents of the GlobalAlloc memory address at runtime, it appears to be entirely valid as a string. But why does SetDlgItemText crash? Thanks. :)
"To deny our impulses... foolish; to revel in them, chaos." MCJ 2003.08

Dark Schneider

#1
I'm not sure about this one but here it goes...

You didn't called GlobalLock so you can't just pass the handle you get right away.
When calling GlobalAlloc, try using GMEM_FIXED flag to get a passable address returned in EAX and you may pass it to SetDlgItemText.

- - - - - - - - - - - - - - - - - - - -
untested code
- - - - - - - - - - - - - - - - - - - -

Invoke GlobalAlloc, GMEM_FIXED, eax
mov hOpenGlobalAlloc,  eax
   
Invoke ReadFile, hOpenFile, hOpenGlobalAlloc, intOpenFileSize, ADDR intNumBytesRead, 0

; before proceeding you should test EAX here to see if you actually get that data or not

Invoke MessageBox, hWnd, hOpenGlobalAlloc, Addr ofnBuffer, MB_OK
Invoke SetDlgItemText, hWnd, IDC_TSC_EDIT1, hOpenGlobalAlloc

Invoke GlobalFree, hOpenGlobalAlloc
Invoke CloseHandle, hOpenFile

;Try it.  :green

Tedd

Schneider:
GPTR = (GMEM_FIXED or GMEM_ZEROINIT)
So that's not a problem.

Mark:
I don't see anything immediately wrong with that code (at a glance.)
But have a look at the EM_SETHANDLE and EM_GETHANDLE messages - they allow you to get/set the memory the edit box uses (only works for 'system' edit boxes, not richedit.)
No snowflake in an avalanche feels responsible.

Relvinian

Mark,

The two things I noticed from your code with using GlobalAlloc and your SetDlgItemText.

1) Make sure you use GlobalLock which will give you a handle back to the "buffer" portion of your memory.
2) With the value you get back from GlobalLock, it is a POINTER so you don't need to use ADDR in your ReadFile or SetDlgItemText calls.

Make sure you unlock it when done.

Relvinian

Mark Jones

Thanks guys. I originally tried GlobalLock but noticed upon debugging that it did not modify EAX as it returned, so it does not generate a new handle. Reading the Win32.hlp a few times, it sounds like the flag GMEM_FIXED implies that the return value is simply a pointer to the memory (FIXED == already locked.)

hOpenGlobalAlloc at runtime == 0040E0A0, and debugging that offset clearly shows the read filedata there, which consists of a few lines of text. Hmm, aaaha! Found the problem. hOpenGlobalAlloc at runtime is OFFSET 0040E0A0, a dword pointer, not the returned value from GlobalAlloc - the returned value is actually something like 0015E948. So ReadFile was putting the data at the wrong location, overwriting other vars and whatnot. Whoops! Simple confusion between ADDR and Dword PTR. :) Here is the working code:


Invoke CreateFile, Addr ofnBuffer, GENERIC_READ, FILE_SHARE_READ, \  ; open file
0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0                           ; handle in eax
Mov hOpenFile, Eax                                                   ; save file handle
Invoke GetFileSize, Eax, NULL                                        ; get size
Inc Eax                                                              ; add a null
Mov intOpenFileSize, Eax                                             ; save
Invoke GlobalAlloc, GPTR, Eax                                        ; allocate sizeof file + 1
Mov hOpenGlobalAlloc, Eax                                            ; save GlobalAlloc handle
Invoke ReadFile, hOpenFile, Dword Ptr hOpenGlobalAlloc,\             ; read file into ram
DWord Ptr intOpenFileSize, Addr intNumBytesRead, 0
Invoke SetDlgItemText, hWnd, IDC_TSC_EDIT1, Dword Ptr hOpenGlobalAlloc
Invoke CloseHandle, hOpenFile                                        ; close file
Invoke GlobalFree, hOpenGlobalAlloc                                  ; free memory
"To deny our impulses... foolish; to revel in them, chaos." MCJ 2003.08

Grincheux

Why do you use GlobalAlloc/GlobalLock ?
If you used VirtualAlloc you make the same thing with only one call ?

Philippe
Kenavo

Grincheux
_____________________________________________________
http://www.phrio.biz

Tedd

Note to everyone who suggests using GlobalLock:

When using GlobalAlloc with GMEM_FIXED (or GPTR) there's no need to lock it - it's allocated immediately and returns the address of the memory block, not the memory handle.
So attempting to lock it will obviously fail.
No snowflake in an avalanche feels responsible.

Relvinian

Quote from: IDCat on March 09, 2005, 07:30:31 PM
Why do you use GlobalAlloc/GlobalLock ?
If you used VirtualAlloc you make the same thing with only one call ?

Philippe

The only reason I would use GlobalAlloc is for the Win32 APIs which require a HGLOBAL handle. This type of allocation isn't defined with GMEM_FIXED but GMEM_MOVABLE.

Otherwise, for the majority of my allocations, I use HeapAlloc and VirtualAlloc.

There are times when I may use other allocating routines if I know I'm going to use different API calls which may require some other type of allocations.

Relvinian

Mark Jones

I chose GlobalAlloc because of its simplicity: just feed it a size and it spits out a R/W mem pointer, no fuss. But VirtualAlloc has some cool features.
"To deny our impulses... foolish; to revel in them, chaos." MCJ 2003.08

Dark Schneider

Tedd:

hmmm... I forgot about that one.

Mark Jones:

I think dword ptr is not needed, did you tried my code above?

Mark Jones

Indeed, it works without the Dword Ptr. Sometimes assembler is so confusing: addr, offset, dword ptr, dereferencing, etc. Some commands want pointers, some want offsets, some want data... :dazzled:  Sometimes I just try all the qualifiers until one works. That and parse the output in Ollydbg - Ctrl-F, "NOP", enter, F2, F9. Repeat Ad Nauseum. :)

I see that edit boxes have their own default buffer. Apparently this can be directly accessed by:

1. Retrieve the handle of the buffer currently allocated by sending the control an EM_GETHANDLE msg.
2. Free the buffer by calling the LocalFree function.
3. Obtain a new buffer (and buffer handle) by calling LocalAlloc. (GlobalAlloc is the same in Win32)
4. Give the buffer handle to Windows by sending the control an EM_SETHANDLE message.


I'll try that next, to eliminate the redundant buffering. :)

よろしく、
マルク
"To deny our impulses... foolish; to revel in them, chaos." MCJ 2003.08