ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

Ruby操作Windows剪贴板

2022-08-12 22:33:06  阅读:390  来源: 互联网

标签:剪贴板 end hmem Windows hwnd void text Ruby def


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# Copyright © 2022, 飞麦 <fitmap@qq.com>, All rights reserved.

# frozen_string_literal: true

require 'fiddle/import'

# Clipboard only for Windows, can use both in x86 and x64
# size_t and handles must use void* (NOT uint) in Fiddle to fit the pointer size of x86 or x64
# if use size_t as return value, you need add to_i to it.
module Clipboard
  module_function

  extend Fiddle::Importer
  include Fiddle::CParser

  dlload 'kernel32', 'user32'

  # HWND GetClipboardOwner();
  extern 'void* GetClipboardOwner()'

  # HWND GetClipboardViewer();
  extern 'void* GetClipboardViewer()'

  # HWND GetDesktopWindow();
  extern 'void* GetDesktopWindow()'

  # BOOL OpenClipboard(
  #   _In_opt_ HWND hWndNewOwner
  # );
  extern 'int OpenClipboard(void*)'

  # BOOL CloseClipboard();
  extern 'int CloseClipboard()'

  # BOOL EmptyClipboard();
  extern 'int EmptyClipboard()'

  # Predefined Clipboard Formats
  CF_UNICODETEXT = 13

  # HANDLE GetClipboardData(
  #   _In_ UINT uFormat
  # );
  extern 'void* GetClipboardData(uint)'

  # HANDLE SetClipboardData(
  #   _In_     UINT   uFormat,
  #   _In_opt_ HANDLE hMem
  # );
  extern 'void* SetClipboardData(uint, void*)'

  # Global Memory Flags
  GMEM_FIXED = 0x0000 # Don't use GMEM_MOVEABLE = 0x0002(need GlobalLock and GlobalUnlock)

  # HGLOBAL GlobalAlloc(
  #   _In_ UINT   uFlags,
  #   _In_ SIZE_T dwBytes
  # );
  extern 'void* GlobalAlloc(uint, void*)'

  # SIZE_T GlobalSize(
  #   _In_ HGLOBAL hMem
  # );
  extern 'void* GlobalSize(void*)'

  # void RtlCopyMemory(
  #   _In_       PVOID  Destination,
  #   _In_ const VOID   *Source,
  #   _In_       SIZE_T Length
  # );
  extern 'void RtlCopyMemory(void*, const void*, void*)'

  # DWORD GetLastError();
  extern 'uint GetLastError()'

  def show(_str)
    # puts _str # uncomment only when debug
    nil
  end

  def clip_hwnd
    hwnd = GetClipboardOwner()
    show("GetClipboardOwner fail! Error=#{GetLastError()}") if hwnd.null?
    hwnd.null? ? nil : hwnd
  end

  def view_hwnd
    hwnd = GetClipboardViewer()
    show("GetClipboardViewer fail! Error=#{GetLastError()}") if hwnd.null?
    hwnd.null? ? nil : hwnd
  end

  def desk_hwnd
    GetDesktopWindow()
  end

  def find_hwnd
    clip_hwnd || view_hwnd || desk_hwnd
  end

  # Sometimes OpenClipboard will fail without any error, so we need retry
  def open_cb
    999.times do
      hwnd = find_hwnd
      next unless hwnd

      break unless OpenClipboard(hwnd).zero?

      show("OpenClipboard fail! Error=#{GetLastError()}")
    end
  end

  def empty_cb
    999.times do
      break unless EmptyClipboard().zero?

      show("EmptyClipboard fail! Error=#{GetLastError()}")
    end
  end

  def close_cb
    999.times do
      break unless CloseClipboard().zero?

      show("CloseClipboard fail! Error=#{GetLastError()}")
    end
  end

  def move_it(text)
    text_16le = "#{text}\u0000".encode(Encoding::UTF_16LE) # must append \u0000 for text
    len = text_16le.bytesize
    hmem = GlobalAlloc(GMEM_FIXED, len)
    show("#GlobalAlloc fail! Error=#{GetLastError()}") if hmem.null?
    RtlCopyMemory(hmem, text_16le, len)
    hmem
  end

  def save_it(hmem)
    hndl = SetClipboardData(CF_UNICODETEXT, hmem)
    show("#SetClipboardData Error=#{GetLastError()} hmem=#{hmem.to_i} != hndl=#{hndl.to_i}") if hndl != hmem
  end

  def copy(text)
    open_cb
    empty_cb
    hmem = move_it(text)
    save_it(hmem)
    close_cb
  end

  def clear
    open_cb
    empty_cb
    close_cb
  end

  def load_it(hmem)
    len = GlobalSize(hmem).to_i
    show("GlobalSize Error=#{GetLastError()} len=#{len}") if len.zero?
    len -= 2 # needn't copy tail \u0000
    text = ''.encode(Encoding::UTF_16LE) * (len / 2)
    RtlCopyMemory(text, hmem, len)
    text.encode(Encoding::UTF_8)
  end

  def paste
    open_cb
    hmem = GetClipboardData(CF_UNICODETEXT)
    text = hmem.null? ? '' : load_it(hmem)
    close_cb
    text
  end
end

标签:剪贴板,end,hmem,Windows,hwnd,void,text,Ruby,def
来源: https://www.cnblogs.com/fitmap/p/16581575.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有