We've all heard that you can't disable the Print Screen key in Windows, which means $KeepPrivate and setting the form properties to disable printing were of limited use. It turns out that Windows has had a way to do it since Windows 95, and it's still present in Windows XP and Vista: RegisterHotKey.
A Limitation That Works To Our Benefit
According to the MSDN documentation, "the RegisterHotKey function defines a system-wide hot key." Furthermore "the system posts the WM_HOTKEY message to the message queue of the window with which the hot key is associated." So what does that mean to you?
Whenever anything happens in Windows, messages are generated. Applications respond to these messages either by handling them or surfacing them as events for developers. That's how Notes uses Ctrl+A to select all the documents in a view, but when a user double-clicks on a document you have an event you can program. It's all about the messages, and who handles them.
In some other development environments you can create your own message handler, or hook. Notes doesn't allow you do that kind of low-level integration, and while that's frustrating for me in this case that works to our benefit! All you have to do is reset the Print Screen key so it gets directed to Notes. Notes isn't programmed to be aware of the message so it gets ignored. The end result is the Print Screen gets pressed and absolutely nothing happens.
The Code
(Declarations)
Declare Function FindWindowByClass Lib "user32" Alias "FindWindowA" (Byval lpClassName As String, Byval lpWindowName As Long) As Long
Declare Function GetTickCount Lib "kernel32" () As Long
Declare Function RegisterHotKey Lib "user32" (Byval hWnd As Long, Byval id As Long, Byval fsModifiers As Long, Byval vk As Long) As Long
Declare Function UnregisterHotKey Lib "user32" (Byval hWnd As Long, Byval id As Long) As Long
Declare Function GlobalAddAtom Lib "kernel32" Alias "GlobalAddAtomA" (Byval lpString As String) As Long
Declare Function GlobalDeleteAtom Lib "kernel32" (Byval nAtom As Long) As Long
Declare Function GetActiveWindow Lib "user32" Alias "GetActiveWindow" () As Long
Const VK_SNAPSHOT = &H2C
Const MOD_ALT = &H1
Const MOD_CONTROL = &H2
Const MOD_SHIFT = &H4
Dim g_hWnd As Long
Dim g_Print As Long
Dim g_AltPrint As Long
Dim g_CtrlPrint As Long
Dim g_ShiftPrint As Long
Sub Queryopen(Source As Notesuidocument, Mode As Integer, Isnewdoc As Variant, Continue As Variant)
'Get a handle to the Notes client window so you can tell Windows which window to hook the hotkeys to
g_hWnd = FindWindowByClass("Notes", 0)
'Register new identifiers for our custom hotkeys. GetTickCount returns a number that's based on the system clock,
' so you know it won't be duplicated.
g_Print = GlobalAddAtom(Cstr(GetTickCount))
g_AltPrint = GlobalAddAtom(Cstr(g_Print) + Cstr(GetTickCount))
g_CtrlPrint = GlobalAddAtom(Cstr(g_AltPrint) + Cstr(GetTickCount))
g_ShiftPrint = GlobalAddAtom(Cstr(g_CtrlPrint) + Cstr(GetTickCount))
'Now register the hotkeys
Call RegisterHotKey(g_hWnd, g_Print, 0&, VK_SNAPSHOT) 'PrintScreen
Call RegisterHotKey(g_hWnd, g_AltPrint, MOD_ALT, VK_SNAPSHOT) 'Alt+PrintScreen
Call RegisterHotKey(g_hWnd, g_CtrlPrint, MOD_CONTROL, VK_SNAPSHOT) 'Ctrl+PrintScreen
Call RegisterHotKey(g_hWnd, g_ShiftPrint, MOD_SHIFT, VK_SNAPSHOT) 'Shift+PrintScreen
End Sub
Sub Queryclose(Source As Notesuidocument, Continue As Variant)
'Unregister the hotkeys
Call UnregisterHotKey(g_hWnd, g_Print)
Call UnregisterHotKey(g_hWnd, g_AltPrint)
Call UnregisterHotKey(g_hWnd, g_CtrlPrint)
Call UnregisterHotKey(g_hWnd, g_ShiftPrint)
'Delete our custom entries
Call GlobalDeleteAtom(g_Print)
Call GlobalDeleteAtom(g_AltPrint)
Call GlobalDeleteAtom(g_CtrlPrint)
Call GlobalDeleteAtom(g_ShiftPrint)
End Sub
provided by Julian Robichaux at nsftools.com.
The Downside
Come on... you knew it couldn't be all good. :-) While this code in active Print Screen is disabled SYSTEM WIDE. Here I have it enabled in a form's QueryOpen, but you could do some tests, say for $KeepPrivate or check user roles, to enable it selectively. (Yes, I know end users can remove $KeepPrivate.) If I put this into production I would be nice and actually tell them that Print Screen is disabled, though. I'll leave that as an exercise for the reader.
Sources: Digital Inspiration blog
Answers.Com RegisterHotKey sample
vbAccelerator clsRegHotKey
[Update 5/16/08 - Removed two unused constants]
2 comments:
huh. that's pretty cool. doesn't defeat my camera though. ;-)
No, it doesn't, and there are a few other techniques someone could use to clip the screen. But it does finally lay to rest the fallacy that you can't disable Print Screen. :-p
Post a Comment