Part of some code I found.
1. Could I incorporate my code to send text to the clipboard in this sequence?
Since I want to be able to paste multiple texts using hot keys, this won't work for the goal in mind.
(Or will it, hmmm.)
I'll have to send the text fragments "elsewhere".
Maybe to the registry. (I keep it lean.)
P.S. Nasal polyps suk.
main proc
local msg:MSG
invoke RegisterHotKey,0,0,MOD_WIN,VK_L ; Windows Key + L
again:
invoke GetMessage,addr msg,0,0,0
.if msg.message==786
call LockWindowStat
.endif
ret
main endp
invoke ExitProcess,0
end start
main proc
local msg:MSG
invoke RegisterHotKey,0,0,MOD_WIN,VK_L ; Windows Key + L
again:
invoke GetMessage,addr msg,0,0,0
.if msg.message==786
call LockWindowStat
.endif
ret
main endp
invoke ExitProcess,0
end start
main proc
local msg:MSG
invoke RegisterHotKey,0,0,MOD_WIN,VK_L ; Windows Key + L
again:
invoke GetMessage,addr msg,0,0,0
.if msg.message==786
call LockWindowStat
.endif
ret
main endp
invoke ExitProcess,0
end start
pasted it 3 times to make it 3 times better? :)
use Michael's code to get the proper sequence....
the masm32 library version (SetClipboardText in setcbtxt.asm) seems to be different - not sure if that is good or bad
but, Michael's code follows the MSDN example code sequence
the only thing missing is GlobalFree at the end
http://www.masm32.com/board/index.php?topic=3879.msg28908#msg28908
as for pasting "multiple text" into the clipboard
you are going to have a problem if other programs access the clipboard
if you leave the clipboard open, they won't be able to copy/paste
if you close it, then your previous stuff may be overwritten
what you might do, is to keep a running buffer, so that it always has the complete clipboard data you want to appear
if i remember right you don't do the global free, you let the clipboard handle that...
well - i use a tool that tells me it leaves a memory leak
http://www.runtimechecker.com/
MS documents say that the OS takes ownership of the memory object
apparently, that does not mean you do not have to release the handle :P
MSDN: SetClipboardData (http://msdn.microsoft.com/en-us/library/ms649051(VS.85).aspx)
Quote
If SetClipboardData succeeds, the system owns the object identified by the hMem parameter. The application may not write to or free the data once ownership has been transferred to the system, but it can lock and read from the data until the CloseClipboard function is called. (The memory must be unlocked before the Clipboard is closed.) If the hMem parameter identifies a memory object, the object must have been allocated using the function with the GMEM_MOVEABLE flag.
I took this at face value when I created the example, but now that I test a GlobalFree at the end does return success, but as a result the memory usage shown in task manager increases by 4KB. I suspect that your tool is simply looking for a free of each handle, and reporting a leak when it does not find one.
the way i read that, once you have closed the clipboard, you should free the allocation as normal
here is the order i am working on...
alloc GMEM_MOVEABLE or GMEM_DDESHARE (for 16-bit compat)
*
open NULL
*
empty
lock
copy
set CF_TEXT
*
unlock
close
free
the asterisks indicate error checks
Quote from: MichaelW on December 17, 2010, 04:28:52 PM
MSDN: SetClipboardData (http://msdn.microsoft.com/en-us/library/ms649051(VS.85).aspx)
Quote
If SetClipboardData succeeds, the system owns the object identified by the hMem parameter. The application may not write to or free the data once ownership has been transferred to the system, but it can lock and read from the data until the CloseClipboard function is called. (The memory must be unlocked before the Clipboard is closed.) If the hMem parameter identifies a memory object, the object must have been allocated using the function with the GMEM_MOVEABLE flag.
I took this at face value when I created the example, but now that I test a GlobalFree at the end does return success, but as a result the memory usage shown in task manager increases by 4KB. I suspect that your tool is simply looking for a free of each handle, and reporting a leak when it does not find one.
Using RunTimeChecker on my code, after my program had gracefully exited,
I got "one memory block in use".
Good or bad?
well - i think that means a leak :P
i have searched the web, looked at the MSDN example, Michael's example, and the masm32 lib version
the differences i am seeing are as follows
1) the masm32 version uses GMEM_MOVEABLE or GMEM_DDESHARE
including the GMEM_DDESHARE flag shouldn't hurt anything, as it is ignored by newer OS's
2) the order things are done is a little different
it makes sense to me to allocate the memory before opening and emptying the clipboard
this allows for better flow if an error occurs
3) the masm32 lib version allocates 64 bytes more than required by the string
probably a good idea
4) the masm32 lib version uses StrLen to get the string length
i think i would require the length as a parm because the caller probably already knows the length and it is faster
5) discrepency in whether or not to free the global allocation
again - it seems only logical that, once the clipboard has been closed, you should free the allocated block
6) the masm32 lib version makes no error checks
as i outlined above, making some checks is probably a good idea
although, you shouldn't have to check every step
for example, i don't think you'll ever see an error locking/unlocking, so long as the allocation uses the right flag
oh - forgot to mention....
many examples i see do this...
lock
copy
unlock
huh ????? - lol
that makes no sense at all
i think you want to leave it locked during SetClipboardData
THEN unlock
as i recall, the masm32 lib version does it this way
i have modified the order a bit to simplify the code...
alloc GMEM_MOVEABLE or GMEM_DDESHARE (for 16-bit compat)
*
lock
copy
unlock
open NULL
*
empty
set CF_TEXT
*
close
free
the asterisks indicate error checks
here is what i come up with
it needs testing, of course
suggestions are welcome :U
EDIT - removed the code from this post, as it had bugzzz
let's try this one
with error checks and return status in EAX
EDIT - removed the code from this post, as it had bugzzz
i'd like to test it under diff OS's - especially win 7
EDIT - removed the code from this post, as it had bugzzz
Using XP Home Edition Version 2002 Sp2
CPU - main thread, module ntdll
EAX 00000000
ECX 77D40000 user32.77D40000
EDX 7C97C080 ntdll.7C97C080
EBX 00000000
ESP 0012FEA8
EBP 0012FFA4
ESI 7C90E88E ntdll.ZwTerminateProcess
EDI 00000000
EIP 7C90EB94 ntdll.KiFastSystemCallRet
C 0 ES 0023 32bit 0(FFFFFFFF)
P 1 CS 001B 32bit 0(FFFFFFFF)
A 0 SS 0023 32bit 0(FFFFFFFF)
Z 1 DS 0023 32bit 0(FFFFFFFF)
S 0 FS 003B 32bit 7FFDE000(FFF)
T 0 GS 0000 NULL
D 0
O 0 LastErr 00000000 ERROR_SUCCESS
EFL 00000246 (NO,NB,E,BE,NS,PE,GE,LE)
ST0 empty +UNORM 0002 00000017 00000020
ST1 empty +UNORM 001B 00000000 7FFDFC00
ST2 empty +UNORM 0045 0208002E 00000000
ST3 empty +UNORM 0003 00000000 0000002E
ST4 empty -UNORM D334 01000003 00000000
ST5 empty -UNORM FC2E 00000000 00000000
ST6 empty -UNORM D20C 0000DCE1 7C91094E
ST7 empty -UNORM D5C4 7C90EE18 0012D54C
3 2 1 0 E S P U O Z D I
FST 0000 Cond 0 0 0 0 Err 0 0 0 0 0 0 0 0 (GT)
FCW 027F Prec NEAR,53 Mask 1 1 1 1 1 1
Last cmnd 001B:5AD72679
XMM0 00141378 00000045 7C910732 00140000
XMM1 7C9140BB 0012D2B8 001420A0 00140000
XMM2 FFFFFFFF 7C910738 7C90EE18 0012D4FC
XMM3 00000000 7C9106EB 7C9106AB 7C910732
XMM4 001420A0 00140000 0012D808 0012D830
XMM5 7C90EE18 0012D534 0077012A 0012D2F0
XMM6 7C9106AB 7C910732 FFFFFFFF 7C910738
XMM7 0012D864 0012D870 00000000 7C9106EB
P U O Z D I
MXCSR 00001F80 FZ 0 DZ 0 Err 0 0 0 0 0 0
Rnd NEAR Mask 1 1 1 1 1 1
yah - but does it work ? :P
i have it at around 33500 cycles - lol
not a fast function to start with, i guess
111 bytes
No, Dave,
the MSDN docs clearly tells that you MUST NOT free the handle.
Also, it tells that you should supply an "unlocked" handle to SetClipboardData().
And IMO your code is unnecessarily hard to read (and error-prone to maintain). I'm tempted to call it a mess.
thanks, Andreas :U
it tells you not to free the handle before closing the clipboard
i cannot find the text you speak of
as for the locked/unlocked - thanks - i'll look into that
as for it being a mess - it is a matter of taste, i think
to each his own
QuoteThe memory must be unlocked before the Clipboard is closed.
ok - have to fix that one
Here's the sample copied from MSDN. Doesn't contain GlobalFree():
BOOL WINAPI EditCopy(VOID)
{
PLABELBOX pbox;
LPTSTR lptstrCopy;
HGLOBAL hglbCopy;
int ich1, ich2, cch;
if (hwndSelected == NULL)
return FALSE;
// Open the clipboard, and empty it.
if (!OpenClipboard(hwndMain))
return FALSE;
EmptyClipboard();
// Get a pointer to the structure for the selected label.
pbox = (PLABELBOX) GetWindowLong(hwndSelected, 0);
// If text is selected, copy it using the CF_TEXT format.
if (pbox->fEdit)
{
if (pbox->ichSel == pbox->ichCaret) // zero length
{
CloseClipboard(); // selection
return FALSE;
}
if (pbox->ichSel < pbox->ichCaret)
{
ich1 = pbox->ichSel;
ich2 = pbox->ichCaret;
}
else
{
ich1 = pbox->ichCaret;
ich2 = pbox->ichSel;
}
cch = ich2 - ich1;
// Allocate a global memory object for the text.
hglbCopy = GlobalAlloc(GMEM_MOVEABLE,
(cch + 1) * sizeof(TCHAR));
if (hglbCopy == NULL)
{
CloseClipboard();
return FALSE;
}
// Lock the handle and copy the text to the buffer.
lptstrCopy = GlobalLock(hglbCopy);
memcpy(lptstrCopy, &pbox->atchLabel[ich1],
cch * sizeof(TCHAR));
lptstrCopy[cch] = (TCHAR) 0; // null character
GlobalUnlock(hglbCopy);
// Place the handle on the clipboard.
SetClipboardData(CF_TEXT, hglbCopy);
}
// If no text is selected, the label as a whole is copied.
else
{
// Save a copy of the selected label as a local memory
// object. This copy is used to render data on request.
// It is freed in response to the WM_DESTROYCLIPBOARD
// message.
pboxLocalClip = (PLABELBOX) LocalAlloc(
LMEM_FIXED,
sizeof(LABELBOX)
);
if (pboxLocalClip == NULL)
{
CloseClipboard();
return FALSE;
}
memcpy(pboxLocalClip, pbox, sizeof(LABELBOX));
pboxLocalClip->fSelected = FALSE;
pboxLocalClip->fEdit = FALSE;
// Place a registered clipboard format, the owner-display
// format, and the CF_TEXT format on the clipboard using
// delayed rendering.
SetClipboardData(uLabelFormat, NULL);
SetClipboardData(CF_OWNERDISPLAY, NULL);
SetClipboardData(CF_TEXT, NULL);
}
// Close the clipboard.
CloseClipboard();
return TRUE;
}
Quote
as for it being a mess - it is a matter of taste, i think to each his own
Usually I'd agree, but in the Campus you'll scare newbies away with such code.
now, i'm trying to find where it says the allocated block needs to be locked at all
it is in the example code, but i do not find it in the documentation text
Quote from: dedndave on December 17, 2010, 07:32:32 PM
yah - but does it work ? :P
i have it at around 33500 cycles - lol
not a fast function to start with, i guess
111 bytes
I need some more info.
What should I look for to determine if it worked?
well, Andy - it has to set the text :P
but i am at a little bit of a loss at the moment, as to whether or not GlobalLock is required
when i have more time, i will re-read the documents completely
WOW, it copies a picture of a naked woman to my clipboard in Win7!!! No, seriously, the test string gets copied to CB
Quote from: dedndave on December 17, 2010, 08:37:01 PM
well, Andy - it has to set the text :P
but i am at a little bit of a loss at the moment, as to whether or not GlobalLock is required
when i have more time, i will re-read the documents completely
It works on my system.
Andy
ok - i have the bugs worked out
from MSDN...
QuoteIf SetClipboardData succeeds, the system owns the object identified by the hMem parameter. The application may not write to or free the data once
ownership has been transferred to the system, but it can lock and read from the data until the CloseClipboard function is called. (The memory must be unlocked
before the Clipboard is closed.) If the hMem parameter identifies a memory object, the object must have been allocated using the function with the
GMEM_MOVEABLE flag.
at any rate, here it is - all cleaned up and ready for testing
it is some 10,000 cycles faster, too - hopefully a sign that things are working right
test program removed - needs work
Here is another test that shows, at least under Windows 2000, no leak through a million iterations.
;====================================================================
include \masm32\include\masm32rt.inc
include \masm32\include\psapi.inc
includelib \masm32\lib\psapi.lib
;====================================================================
PROCESS_MEMORY_COUNTERS STRUCT
cb DWORD ?
PageFaultCount DWORD ?
PeakWorkingSetSize DWORD ?
WorkingSetSize DWORD ?
QuotaPeakPagedPoolUsage DWORD ?
QuotaPagedPoolUsage DWORD ?
QuotaPeakNonPagedPoolUsage DWORD ?
QuotaNonPagedPoolUsage DWORD ?
PagefileUsage DWORD ?
PeakPagefileUsage DWORD ?
PROCESS_MEMORY_COUNTERS ENDS
;====================================================================
testloop MACRO loopcount, freeflag
mov ebx, loopcount
.WHILE ebx
invoke OpenClipboard, NULL
.IF eax
invoke EmptyClipboard
invoke GlobalAlloc, GMEM_MOVEABLE, SIZEOF str1
.IF eax
mov hglb, eax
invoke GlobalLock, hglb
invoke MemCopy, ADDR str1, eax, SIZEOF str1
invoke GlobalUnlock, hglb
invoke SetClipboardData, CF_TEXT, hglb
.IF eax == 0
print "SetClipboardData failed",13,10
.ENDIF
.ELSE
print "GlobalAlloc failed",13,10
.ENDIF
invoke CloseClipboard
.ELSE
print "OpenClipboard failed",13,10
.ENDIF
.IF freeflag
invoke GlobalFree, hglb
.ENDIF
dec ebx
.ENDW
ENDM
;====================================================================
.data
hProcess dd 0
hglb dd 0
pmc PROCESS_MEMORY_COUNTERS <>
str1 db "my other brother darryl",0
.code
;====================================================================
start:
;====================================================================
invoke GetCurrentProcess
mov hProcess, eax
print "Running 1 loop, without free:",13,10
testloop 1, 0
invoke GetProcessMemoryInfo, hProcess, ADDR pmc, SIZEOF pmc
print str$(pmc.WorkingSetSize),9
print str$(pmc.PeakWorkingSetSize),13,10
invoke GlobalFree, hglb
print "Running 1000000 loops, without free:",13,10
testloop 1000000, 0
invoke GetProcessMemoryInfo, hProcess, ADDR pmc, SIZEOF pmc
print str$(pmc.WorkingSetSize),9
print str$(pmc.PeakWorkingSetSize),13,10
invoke GlobalFree, hglb
print "Running 1 loop, with free:",13,10
testloop 1, 1
invoke GetProcessMemoryInfo, hProcess, ADDR pmc, SIZEOF pmc
print str$(pmc.WorkingSetSize),9
print str$(pmc.PeakWorkingSetSize),13,10
print "Running 1000000 loops, with free:",13,10
testloop 1000000, 1
invoke GetProcessMemoryInfo, hProcess, ADDR pmc, SIZEOF pmc
print str$(pmc.WorkingSetSize),9
print str$(pmc.PeakWorkingSetSize),13,10
inkey "Press any key to exit..."
exit
;====================================================================
end start
Running 1 loop, without free:
917504 917504
Running 1000000 loops, without free:
921600 921600
Running 1 loop, with free:
921600 921600
Running 1000000 loops, with free:
921600 921600
Press any key to exit...
i get some odd results when testing 100,000 iterations:
if i use GlobalFree, RuntimeChecker shows clean results - no leaks
if i do not use GlobalFree, RuntimeChecker shows 2 occurances of 152 bytes total
the unterminated string is 11 bytes - the routine allocates 11+65=76 per allocation
i am not sure how to interpret this information
on the one hand, i get no leaks and no errors by doing it the way i think is correct - lol
on the other hand, i would expect 100,000 occurances the other way
in any case, using GlobalFree does not seem to have any detrimental effects
tomorrow, i may see if i can make it do bad things
like - using GlobalFree, then trying to allocate a large block and seeing if the clipboard data is still intact
i would think that using GlobalFree when we shouldn't it should show itself
ok
i managed to break things by using global free
however, if SetClipboardData fails, then the allocation should be freed
so, i have changed the order of things to...
open clipboard NULL
* if error, goto x2
global alloc GMEM_MOVEABLE or GMEM_DDESHARE
* if error, goto x1
empty clipboard
global lock
copy text to mem pointer
global unlock
set clipboard data CF_TEXT
* if no error, goto x1
global free
x1:
close clipboard
x2:
the asterisks indicate error checks
return:
0 success
1 set clipboard data failed
2 global alloc failed
3 open clipboard failed
If you are interested, I have some code that is leak free.
Don't know how fast it is though.
thanks Andy
speed isn't really a critical issue because the API functions are slow as hell, anyways
but it is interesting to note the speed - maybe it's telling us if something is wrong
with some code sequences, i get a time around 33,500 cycles and with others i get a time around 23,500
i think using the right sequence and properly handling errors are important
also, returning a status code, as opposed to displaying an error string, will make the routine usable in native, GUI and console mode programs
Good luck in your project.
Since my program uses the clipboard to store the text for the Keyboard shortcut keys ,
a second program using a different key combination overwrites the first.
And then there is the issue of my programs taking up some "real estate".
Hopeful I can find some way to store the text somewhere else.
I am happy that I have learned a lot of new material.
well - i have a routine that passes all my tests - lol
let's see if it passes everyone else's.....
Works on XP Home Sp2
thanks Andy :U
i have checked it with RuntimeChecker
no matter how many times it is called, it leaves 1 Global handle opened
i suspect that is proper behaviour - the OS closes the others as it discards them
i am going to write a little "wrapper" function that adds the code tags :P
What do you mean a wrapper with code tags?
I have several variants of code that send text to the CB.
One of the versions had no "leaked blocks."
Some advice that someone gave me concerning finding the leak.
< And it should be telling you something about where the block was
< allocated., including, if symbols are available, a good chunk of the
< call stack leading to the allocation.
the last version is leak-free, Andy :P
what i meant by code tags...
are the [ code ] and [ /code ] tags for pasting text into the forum
i have a little routine that adds them to the paste text, then calls the SetCbTxt function
...although, it might be better to write it as a self-contained modified version
Dave,
Running your code under Windows 2000 I cannot detect any significant difference in the memory usage with or without the GlobalFree, even with a much larger number of iterations and a much larger string (I added the "significant" qualifier because I occasionally see a 4KB difference in the numbers). Within the loop the first call to GlobalAlloc increases the memory usage, and with or without the GlobalFree subsequent calls to GlobalAlloc do not increase it further.