1 |
/* Tera Term |
2 |
Copyright(C) 1994-1998 T. Teranishi |
3 |
All rights reserved. */ |
4 |
|
5 |
/* TERATERM.EXE, Clipboard routines */ |
6 |
#include "teraterm.h" |
7 |
#include "tttypes.h" |
8 |
#include "vtdisp.h" |
9 |
#include <string.h> |
10 |
#include <stdlib.h> |
11 |
#include <stdio.h> |
12 |
|
13 |
#include "ttwinman.h" |
14 |
#include "ttcommon.h" |
15 |
|
16 |
#include "clipboar.h" |
17 |
#include "tt_res.h" |
18 |
|
19 |
// for clipboard copy |
20 |
static HGLOBAL CBCopyHandle = NULL; |
21 |
static PCHAR CBCopyPtr = NULL; |
22 |
|
23 |
// for clipboard paste |
24 |
static HGLOBAL CBMemHandle = NULL; |
25 |
static PCHAR CBMemPtr = NULL; |
26 |
static LONG CBMemPtr2 = 0; |
27 |
static BOOL CBAddCR = FALSE; |
28 |
static BYTE CBByte; |
29 |
static BOOL CBRetrySend; |
30 |
static BOOL CBRetryEcho; |
31 |
static BOOL CBSendCR; |
32 |
static BOOL CBDDE; |
33 |
|
34 |
static HFONT DlgClipboardFont; |
35 |
|
36 |
PCHAR CBOpen(LONG MemSize) |
37 |
{ |
38 |
if (MemSize==0) return (NULL); |
39 |
if (CBCopyHandle!=NULL) return (NULL); |
40 |
CBCopyPtr = NULL; |
41 |
CBCopyHandle = GlobalAlloc(GMEM_MOVEABLE, MemSize); |
42 |
if (CBCopyHandle == NULL) |
43 |
MessageBeep(0); |
44 |
else { |
45 |
CBCopyPtr = GlobalLock(CBCopyHandle); |
46 |
if (CBCopyPtr == NULL) |
47 |
{ |
48 |
GlobalFree(CBCopyHandle); |
49 |
CBCopyHandle = NULL; |
50 |
MessageBeep(0); |
51 |
} |
52 |
} |
53 |
return (CBCopyPtr); |
54 |
} |
55 |
|
56 |
void CBClose() |
57 |
{ |
58 |
BOOL Empty; |
59 |
if (CBCopyHandle==NULL) return; |
60 |
|
61 |
Empty = FALSE; |
62 |
if (CBCopyPtr!=NULL) |
63 |
Empty = (CBCopyPtr[0]==0); |
64 |
|
65 |
GlobalUnlock(CBCopyHandle); |
66 |
CBCopyPtr = NULL; |
67 |
|
68 |
if (OpenClipboard(HVTWin)) |
69 |
{ |
70 |
EmptyClipboard(); |
71 |
if (! Empty) |
72 |
SetClipboardData(CF_TEXT, CBCopyHandle); |
73 |
CloseClipboard(); |
74 |
} |
75 |
CBCopyHandle = NULL; |
76 |
} |
77 |
|
78 |
void CBStartPaste(HWND HWin, BOOL AddCR, |
79 |
int BuffSize, PCHAR DataPtr, int DataSize) |
80 |
// |
81 |
// DataPtr and DataSize are used only for DDE |
82 |
// For clipboard, BuffSize should be 0 |
83 |
// DataSize should be <= BuffSize |
84 |
{ |
85 |
UINT Cf; |
86 |
|
87 |
if (! cv.Ready) return; |
88 |
if (TalkStatus!=IdTalkKeyb) return; |
89 |
|
90 |
CBAddCR = AddCR; |
91 |
|
92 |
if (BuffSize==0) // for clipboard |
93 |
{ |
94 |
if (IsClipboardFormatAvailable(CF_TEXT)) |
95 |
Cf = CF_TEXT; |
96 |
else if (IsClipboardFormatAvailable(CF_OEMTEXT)) |
97 |
Cf = CF_OEMTEXT; |
98 |
else return; |
99 |
} |
100 |
|
101 |
CBMemHandle = NULL; |
102 |
CBMemPtr = NULL; |
103 |
CBMemPtr2 = 0; |
104 |
CBDDE = FALSE; |
105 |
if (BuffSize==0) //clipboard |
106 |
{ |
107 |
if (OpenClipboard(HWin)) |
108 |
CBMemHandle = GetClipboardData(Cf); |
109 |
if (CBMemHandle!=NULL) TalkStatus=IdTalkCB; |
110 |
} |
111 |
else { // dde |
112 |
CBMemHandle = GlobalAlloc(GHND,BuffSize); |
113 |
if (CBMemHandle != NULL) |
114 |
{ |
115 |
CBDDE = TRUE; |
116 |
CBMemPtr = GlobalLock(CBMemHandle); |
117 |
if (CBMemPtr != NULL) |
118 |
{ |
119 |
memcpy(CBMemPtr,DataPtr,DataSize); |
120 |
GlobalUnlock(CBMemHandle); |
121 |
CBMemPtr=NULL; |
122 |
TalkStatus=IdTalkCB; |
123 |
} |
124 |
} |
125 |
} |
126 |
CBRetrySend = FALSE; |
127 |
CBRetryEcho = FALSE; |
128 |
CBSendCR = FALSE; |
129 |
if (TalkStatus != IdTalkCB) CBEndPaste(); |
130 |
} |
131 |
|
132 |
// �����������N���b�v�{�[�h������DDE�f�[�^���[�������������B |
133 |
// |
134 |
// CBMemHandle�n���h�����O���[�o�������������A�����������I�������������A |
135 |
// �����N���b�v�{�[�h������DDE�f�[�^�������������������������i�j�����������\�������j�B |
136 |
// �����A�f�[�^���� null-terminate �����������������O�����������������A�������f�[�^���� |
137 |
// �����������B |
138 |
// (2006.11.6 yutaka) |
139 |
void CBSend() |
140 |
{ |
141 |
int c; |
142 |
BOOL EndFlag; |
143 |
int SendBytes = 0; |
144 |
|
145 |
if (CBMemHandle==NULL) return; |
146 |
|
147 |
if (CBRetrySend) |
148 |
{ |
149 |
CBRetryEcho = (ts.LocalEcho>0); |
150 |
c = CommTextOut(&cv,(PCHAR)&CBByte,1); |
151 |
CBRetrySend = (c==0); |
152 |
if (CBRetrySend) return; |
153 |
} |
154 |
|
155 |
if (CBRetryEcho) |
156 |
{ |
157 |
c = CommTextEcho(&cv,(PCHAR)&CBByte,1); |
158 |
CBRetryEcho = (c==0); |
159 |
if (CBRetryEcho) return; |
160 |
} |
161 |
|
162 |
CBMemPtr = GlobalLock(CBMemHandle); |
163 |
if (CBMemPtr==NULL) return; |
164 |
|
165 |
do { |
166 |
if (CBSendCR && (CBMemPtr[CBMemPtr2]==0x0a)) |
167 |
CBMemPtr2++; |
168 |
|
169 |
EndFlag = (CBMemPtr[CBMemPtr2]==0); |
170 |
if (! EndFlag) |
171 |
{ |
172 |
CBByte = CBMemPtr[CBMemPtr2]; |
173 |
CBMemPtr2++; |
174 |
// Decoding characters which are encoded by MACRO |
175 |
// to support NUL character sending |
176 |
// |
177 |
// [encoded character] --> [decoded character] |
178 |
// 01 01 --> 00 |
179 |
// 01 02 --> 01 |
180 |
if (CBByte==0x01) /* 0x01 from MACRO */ |
181 |
{ |
182 |
CBByte = CBMemPtr[CBMemPtr2]; |
183 |
CBMemPtr2++; |
184 |
CBByte = CBByte - 1; // character just after 0x01 |
185 |
} |
186 |
} |
187 |
else if (CBAddCR) |
188 |
{ |
189 |
EndFlag = FALSE; |
190 |
CBAddCR = FALSE; |
191 |
CBByte = 0x0d; |
192 |
} |
193 |
else { |
194 |
CBEndPaste(); |
195 |
return; |
196 |
} |
197 |
|
198 |
if (! EndFlag) |
199 |
{ |
200 |
c = CommTextOut(&cv,(PCHAR)&CBByte,1); |
201 |
CBSendCR = (CBByte==0x0D); |
202 |
CBRetrySend = (c==0); |
203 |
if ((! CBRetrySend) && |
204 |
(ts.LocalEcho>0)) |
205 |
{ |
206 |
c = CommTextEcho(&cv,(PCHAR)&CBByte,1); |
207 |
CBRetryEcho = (c==0); |
208 |
} |
209 |
|
210 |
// SSH2 ���������f�[�^���\���t�����������G�R�[�o�b�N�������������� |
211 |
// ���������A500 �o�C�g���M���������� 10ms(�����l������������) ���� |
212 |
// workaround (2008.8.22 maya) |
213 |
SendBytes++; |
214 |
if (SendBytes > 500) { |
215 |
SendBytes = 0; |
216 |
Sleep(10); |
217 |
} |
218 |
} |
219 |
else |
220 |
c=0; |
221 |
} |
222 |
while (c>0); |
223 |
|
224 |
if (CBMemPtr!=NULL) |
225 |
{ |
226 |
GlobalUnlock(CBMemHandle); |
227 |
CBMemPtr=NULL; |
228 |
} |
229 |
} |
230 |
|
231 |
void CBEndPaste() |
232 |
{ |
233 |
TalkStatus = IdTalkKeyb; |
234 |
|
235 |
if (CBMemHandle!=NULL) |
236 |
{ |
237 |
if (CBMemPtr!=NULL) |
238 |
GlobalUnlock(CBMemHandle); |
239 |
if (CBDDE) |
240 |
GlobalFree(CBMemHandle); |
241 |
} |
242 |
if (!CBDDE) CloseClipboard(); |
243 |
|
244 |
CBDDE = FALSE; |
245 |
CBMemHandle = NULL; |
246 |
CBMemPtr = NULL; |
247 |
CBMemPtr2 = 0; |
248 |
CBAddCR = FALSE; |
249 |
} |
250 |
|
251 |
|
252 |
static char *ClipboardPtr = NULL; |
253 |
static int PasteCanceled = 0; |
254 |
|
255 |
static LRESULT CALLBACK OnClipboardDlgProc(HWND hDlgWnd, UINT msg, WPARAM wp, LPARAM lp) |
256 |
{ |
257 |
LOGFONT logfont; |
258 |
HFONT font; |
259 |
char uimsg[MAX_UIMSG]; |
260 |
//char *p; |
261 |
POINT p; |
262 |
RECT rc_dsk, rc_dlg; |
263 |
int dlg_height, dlg_width; |
264 |
OSVERSIONINFO osvi; |
265 |
static int ok2right, info2bottom, edit2ok, edit2info; |
266 |
RECT rc_edit, rc_ok, rc_cancel, rc_info; |
267 |
|
268 |
switch (msg) { |
269 |
case WM_INITDIALOG: |
270 |
#if 0 |
271 |
for (p = ClipboardPtr; *p ; p++) { |
272 |
char buf[20]; |
273 |
_snprintf_s(buf, sizeof(buf), _TRUNCATE, "%02x ", *p); |
274 |
OutputDebugString(buf); |
275 |
} |
276 |
#endif |
277 |
|
278 |
font = (HFONT)SendMessage(hDlgWnd, WM_GETFONT, 0, 0); |
279 |
GetObject(font, sizeof(LOGFONT), &logfont); |
280 |
if (get_lang_font("DLG_TAHOMA_FONT", hDlgWnd, &logfont, &DlgClipboardFont, ts.UILanguageFile)) { |
281 |
SendDlgItemMessage(hDlgWnd, IDC_EDIT, WM_SETFONT, (WPARAM)DlgClipboardFont, MAKELPARAM(TRUE,0)); |
282 |
SendDlgItemMessage(hDlgWnd, IDC_CLIPBOARD_INFO, WM_SETFONT, (WPARAM)DlgClipboardFont, MAKELPARAM(TRUE,0)); |
283 |
SendDlgItemMessage(hDlgWnd, IDOK, WM_SETFONT, (WPARAM)DlgClipboardFont, MAKELPARAM(TRUE,0)); |
284 |
SendDlgItemMessage(hDlgWnd, IDCANCEL, WM_SETFONT, (WPARAM)DlgClipboardFont, MAKELPARAM(TRUE,0)); |
285 |
} |
286 |
else { |
287 |
DlgClipboardFont = NULL; |
288 |
} |
289 |
|
290 |
GetWindowText(hDlgWnd, uimsg, sizeof(uimsg)); |
291 |
get_lang_msg("DLG_CLIPBOARD_TITLE", ts.UIMsg, sizeof(ts.UIMsg), uimsg, ts.UILanguageFile); |
292 |
SetWindowText(hDlgWnd, ts.UIMsg); |
293 |
GetDlgItemText(hDlgWnd, IDC_CLIPBOARD_INFO, uimsg, sizeof(uimsg)); |
294 |
get_lang_msg("DLG_CLIPBOARD_INFO", ts.UIMsg, sizeof(ts.UIMsg), uimsg, ts.UILanguageFile); |
295 |
SetDlgItemText(hDlgWnd, IDC_CLIPBOARD_INFO, ts.UIMsg); |
296 |
GetDlgItemText(hDlgWnd, IDCANCEL, uimsg, sizeof(uimsg)); |
297 |
get_lang_msg("BTN_CANCEL", ts.UIMsg, sizeof(ts.UIMsg), uimsg, ts.UILanguageFile); |
298 |
SetDlgItemText(hDlgWnd, IDCANCEL, ts.UIMsg); |
299 |
GetDlgItemText(hDlgWnd, IDOK, uimsg, sizeof(uimsg)); |
300 |
get_lang_msg("BTN_OK", ts.UIMsg, sizeof(ts.UIMsg), uimsg, ts.UILanguageFile); |
301 |
SetDlgItemText(hDlgWnd, IDOK, ts.UIMsg); |
302 |
|
303 |
SendMessage(GetDlgItem(hDlgWnd, IDC_EDIT), WM_SETTEXT, 0, (LPARAM)ClipboardPtr); |
304 |
|
305 |
DispConvScreenToWin(CursorX, CursorY, &p.x, &p.y); |
306 |
ClientToScreen(HVTWin, &p); |
307 |
|
308 |
// �L�����b�g���������������o���������������\���t���������� |
309 |
// �m�F�E�C���h�E�����������������\���������������������B |
310 |
// �E�C���h�E���������o������������������ (2008.4.24 maya) |
311 |
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); |
312 |
GetVersionEx(&osvi); |
313 |
if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT && osvi.dwMajorVersion == 4) { |
314 |
// NT4.0 ���}���`���j�^API�������� |
315 |
SystemParametersInfo(SPI_GETWORKAREA, 0, &rc_dsk, 0); |
316 |
} |
317 |
else { |
318 |
HMONITOR hm; |
319 |
POINT pt; |
320 |
MONITORINFO mi; |
321 |
|
322 |
pt.x = p.x; |
323 |
pt.y = p.y; |
324 |
hm = MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST); |
325 |
|
326 |
mi.cbSize = sizeof(MONITORINFO); |
327 |
GetMonitorInfo(hm, &mi); |
328 |
rc_dsk = mi.rcWork; |
329 |
} |
330 |
GetWindowRect(hDlgWnd, &rc_dlg); |
331 |
dlg_height = rc_dlg.bottom-rc_dlg.top; |
332 |
dlg_width = rc_dlg.right-rc_dlg.left; |
333 |
if (p.y < rc_dsk.top) { |
334 |
p.y = rc_dsk.top; |
335 |
} |
336 |
else if (p.y + dlg_height > rc_dsk.bottom) { |
337 |
p.y = rc_dsk.bottom - dlg_height; |
338 |
} |
339 |
if (p.x < rc_dsk.left) { |
340 |
p.x = rc_dsk.left; |
341 |
} |
342 |
else if (p.x + dlg_width > rc_dsk.right) { |
343 |
p.x = rc_dsk.right - dlg_width; |
344 |
} |
345 |
|
346 |
SetWindowPos(hDlgWnd, NULL, p.x, p.y, |
347 |
0, 0, SWP_NOSIZE | SWP_NOZORDER); |
348 |
|
349 |
// �����T�C�Y�����K�v���l���v�Z |
350 |
GetClientRect(hDlgWnd, &rc_dlg); |
351 |
GetWindowRect(GetDlgItem(hDlgWnd, IDC_EDIT), &rc_edit); |
352 |
GetWindowRect(GetDlgItem(hDlgWnd, IDOK), &rc_ok); |
353 |
GetWindowRect(GetDlgItem(hDlgWnd, IDC_CLIPBOARD_INFO), &rc_info); |
354 |
|
355 |
p.x = rc_dlg.right; |
356 |
p.y = rc_dlg.bottom; |
357 |
ClientToScreen(hDlgWnd, &p); |
358 |
ok2right = p.x - rc_ok.left; |
359 |
info2bottom = p.y - rc_info.top; |
360 |
edit2ok = rc_ok.left - rc_edit.right; |
361 |
edit2info = rc_info.top - rc_edit.bottom; |
362 |
|
363 |
// �T�C�Y������ |
364 |
SetWindowPos(hDlgWnd, NULL, 0, 0, |
365 |
ts.PasteDialogSize.cx, ts.PasteDialogSize.cy, |
366 |
SWP_NOZORDER | SWP_NOMOVE); |
367 |
|
368 |
return TRUE; |
369 |
|
370 |
case WM_COMMAND: |
371 |
switch (LOWORD(wp)) { |
372 |
case IDOK: |
373 |
{ |
374 |
int len = SendMessage(GetDlgItem(hDlgWnd, IDC_EDIT), WM_GETTEXTLENGTH, 0, 0); |
375 |
HGLOBAL hMem; |
376 |
char *buf; |
377 |
|
378 |
hMem = GlobalAlloc(GMEM_MOVEABLE, len + 1); |
379 |
buf = GlobalLock(hMem); |
380 |
SendMessage(GetDlgItem(hDlgWnd, IDC_EDIT), WM_GETTEXT, len + 1, (LPARAM)buf); |
381 |
GlobalUnlock(hMem); |
382 |
|
383 |
EmptyClipboard(); |
384 |
SetClipboardData(CF_TEXT, hMem); |
385 |
|
386 |
// hMem���N���b�v�{�[�h�������������������A�j�����������������B |
387 |
|
388 |
if (DlgClipboardFont != NULL) { |
389 |
DeleteObject(DlgClipboardFont); |
390 |
} |
391 |
|
392 |
EndDialog(hDlgWnd, IDOK); |
393 |
} |
394 |
break; |
395 |
|
396 |
case IDCANCEL: |
397 |
PasteCanceled = 1; |
398 |
|
399 |
if (DlgClipboardFont != NULL) { |
400 |
DeleteObject(DlgClipboardFont); |
401 |
} |
402 |
|
403 |
EndDialog(hDlgWnd, IDCANCEL); |
404 |
break; |
405 |
|
406 |
default: |
407 |
return FALSE; |
408 |
} |
409 |
|
410 |
#if 0 |
411 |
case WM_CLOSE: |
412 |
PasteCanceled = 1; |
413 |
EndDialog(hDlgWnd, 0); |
414 |
return TRUE; |
415 |
#endif |
416 |
|
417 |
case WM_SIZE: |
418 |
{ |
419 |
// ���z�u |
420 |
POINT p; |
421 |
int dlg_w, dlg_h; |
422 |
|
423 |
GetClientRect(hDlgWnd, &rc_dlg); |
424 |
dlg_w = rc_dlg.right; |
425 |
dlg_h = rc_dlg.bottom; |
426 |
|
427 |
GetWindowRect(GetDlgItem(hDlgWnd, IDC_EDIT), &rc_edit); |
428 |
GetWindowRect(GetDlgItem(hDlgWnd, IDOK), &rc_ok); |
429 |
GetWindowRect(GetDlgItem(hDlgWnd, IDCANCEL), &rc_cancel); |
430 |
GetWindowRect(GetDlgItem(hDlgWnd, IDC_CLIPBOARD_INFO), &rc_info); |
431 |
|
432 |
// OK |
433 |
p.x = rc_ok.left; |
434 |
p.y = rc_ok.top; |
435 |
ScreenToClient(hDlgWnd, &p); |
436 |
SetWindowPos(GetDlgItem(hDlgWnd, IDOK), 0, |
437 |
dlg_w - ok2right, p.y, 0, 0, |
438 |
SWP_NOSIZE | SWP_NOZORDER); |
439 |
|
440 |
// CANCEL |
441 |
p.x = rc_cancel.left; |
442 |
p.y = rc_cancel.top; |
443 |
ScreenToClient(hDlgWnd, &p); |
444 |
SetWindowPos(GetDlgItem(hDlgWnd, IDCANCEL), 0, |
445 |
dlg_w - ok2right, p.y, 0, 0, |
446 |
SWP_NOSIZE | SWP_NOZORDER); |
447 |
|
448 |
// INFO |
449 |
p.x = rc_info.left; |
450 |
p.y = rc_info.top; |
451 |
ScreenToClient(hDlgWnd, &p); |
452 |
SetWindowPos(GetDlgItem(hDlgWnd, IDC_CLIPBOARD_INFO), 0, |
453 |
p.x, dlg_h - info2bottom, 0, 0, |
454 |
SWP_NOSIZE | SWP_NOZORDER); |
455 |
|
456 |
// EDIT |
457 |
p.x = rc_edit.left; |
458 |
p.y = rc_edit.top; |
459 |
ScreenToClient(hDlgWnd, &p); |
460 |
SetWindowPos(GetDlgItem(hDlgWnd, IDC_EDIT), 0, |
461 |
0, 0, dlg_w - p.x - edit2ok - ok2right, dlg_h - p.y - edit2info - info2bottom, |
462 |
SWP_NOMOVE | SWP_NOZORDER); |
463 |
|
464 |
// �T�C�Y������ |
465 |
GetWindowRect(hDlgWnd, &rc_dlg); |
466 |
ts.PasteDialogSize.cx = rc_dlg.right - rc_dlg.left; |
467 |
ts.PasteDialogSize.cy = rc_dlg.bottom - rc_dlg.top; |
468 |
} |
469 |
return TRUE; |
470 |
|
471 |
default: |
472 |
return FALSE; |
473 |
} |
474 |
return TRUE; |
475 |
} |
476 |
|
477 |
// |
478 |
// �N���b�v�{�[�h�����s�R�[�h�����������������A�m�F�_�C�A���O���\�������B |
479 |
// �N���b�v�{�[�h�����X�����\�B |
480 |
// |
481 |
// return 0: Cancel |
482 |
// 1: Paste OK |
483 |
// |
484 |
// (2008.2.3 yutaka) |
485 |
// |
486 |
int CBStartPasteConfirmChange(HWND HWin) |
487 |
{ |
488 |
UINT Cf; |
489 |
HANDLE hText; |
490 |
char *pText; |
491 |
int pos; |
492 |
int ret = 0; |
493 |
|
494 |
if (ts.ConfirmChangePaste == 0) |
495 |
return 1; |
496 |
|
497 |
if (! cv.Ready) |
498 |
goto error; |
499 |
if (TalkStatus!=IdTalkKeyb) |
500 |
goto error; |
501 |
|
502 |
if (IsClipboardFormatAvailable(CF_TEXT)) |
503 |
Cf = CF_TEXT; |
504 |
else if (IsClipboardFormatAvailable(CF_OEMTEXT)) |
505 |
Cf = CF_OEMTEXT; |
506 |
else |
507 |
goto error; |
508 |
|
509 |
if (!OpenClipboard(HWin)) |
510 |
goto error; |
511 |
|
512 |
hText = GetClipboardData(Cf); |
513 |
|
514 |
if (hText != NULL) { |
515 |
pText = (char *)GlobalLock(hText); |
516 |
pos = strcspn(pText, "\r\n"); // ���s���������������� |
517 |
if (pText[pos] != '\0') { |
518 |
ClipboardPtr = pText; |
519 |
PasteCanceled = 0; |
520 |
ret = DialogBox(hInst, MAKEINTRESOURCE(IDD_CLIPBOARD_DIALOG), |
521 |
HVTWin, (DLGPROC)OnClipboardDlgProc); |
522 |
if (ret == 0 || ret == -1) { |
523 |
ret = GetLastError(); |
524 |
} |
525 |
|
526 |
if (PasteCanceled) { |
527 |
ret = 0; |
528 |
GlobalUnlock(hText); |
529 |
CloseClipboard(); |
530 |
goto error; |
531 |
} |
532 |
|
533 |
} |
534 |
|
535 |
ret = 1; |
536 |
|
537 |
GlobalUnlock(hText); |
538 |
} |
539 |
|
540 |
CloseClipboard(); |
541 |
|
542 |
error: |
543 |
return (ret); |
544 |
} |