[Win32utils-devel] Creating a clipboard monitor

Heesob Park phasis at gmail.com
Thu Apr 23 02:47:56 EDT 2009


Hi,

2009/4/23 Daniel Berger <djberg96 at gmail.com>:
> Hi,
>
> I see the Win32::Clipboard module has a WaitForChange() method that waits
> for a change in the Windows clipboard. I'd like to setup something similar
> for the win32-clipboard library, perhaps call it notify_change to match
> win32-eventlog.
>
> I looked at the implementation, and it's similar to others I found online.
> But, it seems like it ought to be easier. Instead of RegisterClass(),
> CreateWindow(), etc, can't we just use the handle of the current process
> instead of injecting a new Window into the clipboard chain?
>
> In any case, I'm not having much luck trying to implement this. I did add
> some methods to the Windows::Window::Classes module that might be necessary.
> Any help here would be greatly appreciated.
>
> In other news, it seems GetWindowLongPtr and SetWindowLongPtr are not
> exported by the runtime that ships with the one-click.
>
> Regards,
>
> Dan
>
> PS - It's a shame they don't provide a NotifyChangeClipboard() function to
> make life easier. :)
>
As you expected, here is a sample code :)

require 'win32/api'
require 'windows/clipboard'
require 'windows/window/classes'
require 'windows/window/message'
require 'windows/library'
require 'windows/window'
require 'win32/clipboard'

include Win32
include Windows::Window
include Windows::Window::Classes
include Windows::Window::Message
include Windows::Library
include Windows::Clipboard

handle = CreateWindow('static','test',0,0,0,0,0,0,0,0,0)

my_wnd_proc = API::Callback.new('LLLL', 'L') do |hwnd,uMsg,wParam,lParam|
  case uMsg
  when 0x0308 # WM_DRAWCLIPBOARD
     puts 'Clipboard Changed'
     puts Clipboard.data
     next_viewer = GetWindowLongPtr(hwnd,GWL_USERDATA)
     if next_viewer != 0
        PostMessage(next_viewer,uMsg,wParam,lParam)
     end
     r = 0
  when 0x030D # WM_CHANGECBCHAIN
     puts 'WM_CHANGECBCHAIN'
     next_viewer = lParam if next_viewer == wParam
	 if next_viewer != 0
	    PostMessage(next_viewer,uMsg,wParam,lParam)
	 end
	 r = 0
  else
	 r = DefWindowProc(hwnd,uMsg,wParam,lParam)
  end
  r
end

old_wnd_proc = SetWindowLongPtr(handle,GWL_WNDPROC,my_wnd_proc.address)
next_viewer = SetClipboardViewer(handle)
SetWindowLongPtr(handle,GWL_USERDATA,next_viewer)

msg = 0.chr * 100
while true
  while(PeekMessage(msg,handle,0,0,1))
     TranslateMessage(msg)
     DispatchMessage(msg)
  end
  sleep 0.1
end


In order to run this code, several changes are required.
1. GetWindowLongPtr and SetWindowLongPtr

In 32bit Windows, GetWindowLongPtr and SetWindowLongPtr are just a
macro of GetWindowLog and SetWindowLong.
Modify windows/window/classes.rb like this would be enough:

         begin
            API.new('GetWindowLongPtr', 'LI', 'L', 'user32')
            API.new('SetWindowLongPtr', 'LIP', 'L', 'user32')
         rescue Win32::API::LoadLibraryError
  	    alias :GetWindowLongPtr :GetWindowLong
	    alias :SetWindowLongPtr :SetWindowLong
         end

2. CreateWindow

In recent version of user32.dll, CreateWindow is not a function but a
macro of CreateWindowEx.
Modify windows/window.rb something like this

	  begin
	     API.new('CreateWindow', 'PPLIIIILLLL', 'L', 'user32')
	  rescue Win32::API::LoadLibraryError
	     def CreateWindow(lpClassName, lpWindowName, dwStyle, x, y,
nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam)
			CreateWindowEx(0,lpClassName, lpWindowName, dwStyle, x, y, nWidth,
nHeight, hWndParent, hMenu, hInstance, lpParam)
		 end
	     def CreateWindowA(lpClassName, lpWindowName, dwStyle, x, y,
nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam)
			CreateWindowExA(0,lpClassName, lpWindowName, dwStyle, x, y, nWidth,
nHeight, hWndParent, hMenu, hInstance, lpParam)
		 end
	     def CreateWindowW(lpClassName, lpWindowName, dwStyle, x, y,
nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam)
			CreateWindowExW(0,lpClassName, lpWindowName, dwStyle, x, y, nWidth,
nHeight, hWndParent, hMenu, hInstance, lpParam)
		 end
	  end

3. GetUpdatedClipboardFormats
GetUpdatedClipboardFormats is supported for Vista or later.
Modify windows/clipboard.rb something like this

      begin
         API.new('GetUpdatedClipboardFormats', 'PIP', 'I', 'user32')
         API.new('AddClipboardFormatListener', 'L', 'B', 'user32')
         API.new('RemoveClipboardFormatListener', 'L', 'B', 'user32')
      rescue Win32::API::LoadLibraryError
         # Windows Vista or later
      end


Regards,

Park Heesob


More information about the win32utils-devel mailing list