Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F36622968
main.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
17 KB
Subscribers
None
main.c
View Options
/* main.c - Secure W32 dialog for PIN entry.
* Copyright (C) 2004, 2007 g10 Code GmbH
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <https://www.gnu.org/licenses/>.
* SPDX-License-Identifier: GPL-2.0+
*/
#include
<config.h>
#include
<stdio.h>
#include
<stdlib.h>
#if WINVER < 0x0403
# define WINVER 0x0403
/* Required for SendInput. */
#endif
#include
<windows.h>
#ifdef HAVE_W32CE_SYSTEM
# include <winioctl.h>
# include <sipapi.h>
#endif
#include
"pinentry.h"
#include
"memory.h"
#include
"resource.h"
/* #include "msgcodes.h" */
#define PGMNAME "pinentry-w32"
#ifndef LSFW_LOCK
# define LSFW_LOCK 1
# define LSFW_UNLOCK 2
#endif
#ifndef debugfp
#define debugfp stderr
#endif
/* This function pointer gets initialized in main. */
#ifndef HAVE_W32CE_SYSTEM
static
BOOL
WINAPI
(
*
lock_set_foreground_window
)(
UINT
);
#endif
static
int
w32_cmd_handler
(
pinentry_t
pe
);
static
void
ok_button_clicked
(
HWND
dlg
,
pinentry_t
pe
);
/* We use global variables for the state, because there should never
ever be a second instance. */
static
HWND
dialog_handle
;
static
int
confirm_mode
;
static
int
passphrase_ok
;
static
int
confirm_yes
;
/* The file descriptors for the loop. */
static
int
w32_infd
;
static
int
w32_outfd
;
/* Connect this module to the pinentry framework. */
pinentry_cmd_handler_t
pinentry_cmd_handler
=
w32_cmd_handler
;
const
char
*
w32_strerror
(
int
ec
)
{
static
char
strerr
[
256
];
if
(
ec
==
-1
)
ec
=
(
int
)
GetLastError
();
#ifdef HAVE_W32CE_SYSTEM
/* There is only a wchar_t FormatMessage. It does not make much
sense to play the conversion game; we print only the code. */
snprintf
(
strerr
,
sizeof
strerr
,
"ec=%d"
,
ec
);
strerr
[
sizeof
strerr
-1
]
=
0
;
#else
FormatMessage
(
FORMAT_MESSAGE_FROM_SYSTEM
,
NULL
,
ec
,
MAKELANGID
(
LANG_NEUTRAL
,
SUBLANG_DEFAULT
),
strerr
,
sizeof
strerr
-
1
,
NULL
);
#endif
return
strerr
;
}
#ifdef HAVE_W32CE_SYSTEM
/* Create a pipe. WRITE_END shall have the opposite value of the one
pssed to _assuan_w32ce_prepare_pipe; see there for more
details. */
#define GPGCEDEV_IOCTL_MAKE_PIPE \
CTL_CODE (FILE_DEVICE_STREAMS, 2049, METHOD_BUFFERED, FILE_ANY_ACCESS)
static
HANDLE
w32ce_finish_pipe
(
int
rvid
,
int
write_end
)
{
HANDLE
hd
;
hd
=
CreateFile
(
L
"GPG1:"
,
write_end
?
GENERIC_WRITE
:
GENERIC_READ
,
FILE_SHARE_READ
|
FILE_SHARE_WRITE
,
NULL
,
OPEN_ALWAYS
,
FILE_ATTRIBUTE_NORMAL
,
NULL
);
if
(
hd
!=
INVALID_HANDLE_VALUE
)
{
if
(
!
DeviceIoControl
(
hd
,
GPGCEDEV_IOCTL_MAKE_PIPE
,
&
rvid
,
sizeof
rvid
,
NULL
,
0
,
NULL
,
NULL
))
{
DWORD
lastrc
=
GetLastError
();
CloseHandle
(
hd
);
hd
=
INVALID_HANDLE_VALUE
;
SetLastError
(
lastrc
);
}
}
return
hd
;
}
#endif
/*HAVE_W32CE_SYSTEM*/
/* static HWND */
/* show_window_hierarchy (HWND parent, int level) */
/* { */
/* HWND child; */
/* child = GetWindow (parent, GW_CHILD); */
/* while (child) */
/* { */
/* char buf[1024+1]; */
/* char name[200]; */
/* int nname; */
/* char *pname; */
/* memset (buf, 0, sizeof (buf)); */
/* GetWindowText (child, buf, sizeof (buf)-1); */
/* nname = GetClassName (child, name, sizeof (name)-1); */
/* if (nname) */
/* pname = name; */
/* else */
/* pname = NULL; */
/* fprintf (debugfp, "### %*shwnd=%p (%s) `%s'\n", level*2, "", child, */
/* pname? pname:"", buf); */
/* show_window_hierarchy (child, level+1); */
/* child = GetNextWindow (child, GW_HWNDNEXT); */
/* } */
/* return NULL; */
/* } */
/* Convert a wchar to UTF8. Caller needs to release the string.
Returns NULL on error. */
static
char
*
wchar_to_utf8
(
const
wchar_t
*
string
,
size_t
len
,
int
secure
)
{
int
n
;
char
*
result
;
/* Note, that CP_UTF8 is not defined in Windows versions earlier
than NT. */
n
=
WideCharToMultiByte
(
CP_UTF8
,
0
,
string
,
len
,
NULL
,
0
,
NULL
,
NULL
);
if
(
n
<
0
)
return
NULL
;
result
=
secure
?
secmem_malloc
(
n
+
1
)
:
malloc
(
n
+
1
);
if
(
!
result
)
return
NULL
;
n
=
WideCharToMultiByte
(
CP_UTF8
,
0
,
string
,
len
,
result
,
n
,
NULL
,
NULL
);
if
(
n
<
0
)
{
if
(
secure
)
secmem_free
(
result
);
else
free
(
result
);
return
NULL
;
}
return
result
;
}
/* Convert a UTF8 string to wchar. Returns NULL on error. Caller
needs to free the returned value. */
wchar_t
*
utf8_to_wchar
(
const
char
*
string
)
{
int
n
;
wchar_t
*
result
;
size_t
len
=
strlen
(
string
);
n
=
MultiByteToWideChar
(
CP_UTF8
,
0
,
string
,
len
,
NULL
,
0
);
if
(
n
<
0
)
return
NULL
;
result
=
calloc
((
n
+
1
),
sizeof
*
result
);
if
(
!
result
)
return
NULL
;
n
=
MultiByteToWideChar
(
CP_UTF8
,
0
,
string
,
len
,
result
,
n
);
if
(
n
<
0
)
{
free
(
result
);
return
NULL
;
}
result
[
n
]
=
0
;
return
result
;
}
/* Raise the software input panel. */
static
void
raise_sip
(
HWND
dlg
)
{
#ifdef HAVE_W32CE_SYSTEM
SIPINFO
si
;
SetForegroundWindow
(
dlg
);
memset
(
&
si
,
0
,
sizeof
si
);
si
.
cbSize
=
sizeof
si
;
if
(
SipGetInfo
(
&
si
))
{
si
.
fdwFlags
|=
SIPF_ON
;
SipSetInfo
(
&
si
);
}
#else
(
void
)
dlg
;
#endif
}
/* Center the window CHILDWND with the desktop as its parent
window. STYLE is passed as second arg to SetWindowPos.*/
static
void
center_window
(
HWND
childwnd
,
HWND
style
)
{
#ifndef HAVE_W32CE_SYSTEM
HWND
parwnd
;
RECT
rchild
,
rparent
;
HDC
hdc
;
int
wchild
,
hchild
,
wparent
,
hparent
;
int
wscreen
,
hscreen
,
xnew
,
ynew
;
int
flags
=
SWP_NOSIZE
|
SWP_NOZORDER
;
parwnd
=
GetDesktopWindow
();
GetWindowRect
(
childwnd
,
&
rchild
);
wchild
=
rchild
.
right
-
rchild
.
left
;
hchild
=
rchild
.
bottom
-
rchild
.
top
;
GetWindowRect
(
parwnd
,
&
rparent
);
wparent
=
rparent
.
right
-
rparent
.
left
;
hparent
=
rparent
.
bottom
-
rparent
.
top
;
hdc
=
GetDC
(
childwnd
);
wscreen
=
GetDeviceCaps
(
hdc
,
HORZRES
);
hscreen
=
GetDeviceCaps
(
hdc
,
VERTRES
);
ReleaseDC
(
childwnd
,
hdc
);
xnew
=
rparent
.
left
+
((
wparent
-
wchild
)
/
2
);
if
(
xnew
<
0
)
xnew
=
0
;
else
if
((
xnew
+
wchild
)
>
wscreen
)
xnew
=
wscreen
-
wchild
;
ynew
=
rparent
.
top
+
((
hparent
-
hchild
)
/
2
);
if
(
ynew
<
0
)
ynew
=
0
;
else
if
((
ynew
+
hchild
)
>
hscreen
)
ynew
=
hscreen
-
hchild
;
if
(
style
==
HWND_TOPMOST
||
style
==
HWND_NOTOPMOST
)
flags
=
SWP_NOMOVE
|
SWP_NOSIZE
;
SetWindowPos
(
childwnd
,
style
?
style
:
NULL
,
xnew
,
ynew
,
0
,
0
,
flags
);
#endif
}
static
void
move_mouse_and_click
(
HWND
hwnd
)
{
#ifndef HAVE_W32CE_SYSTEM
RECT
rect
;
HDC
hdc
;
int
wscreen
,
hscreen
,
x
,
y
,
normx
,
normy
;
INPUT
inp
[
3
];
int
idx
;
hdc
=
GetDC
(
hwnd
);
wscreen
=
GetDeviceCaps
(
hdc
,
HORZRES
);
hscreen
=
GetDeviceCaps
(
hdc
,
VERTRES
);
ReleaseDC
(
hwnd
,
hdc
);
if
(
wscreen
<
10
||
hscreen
<
10
)
return
;
GetWindowRect
(
hwnd
,
&
rect
);
x
=
rect
.
left
;
y
=
rect
.
bottom
;
normx
=
x
*
(
65535
/
wscreen
);
if
(
normx
<
0
||
normx
>
65535
)
return
;
normy
=
y
*
(
65535
/
hscreen
);
if
(
normy
<
0
||
normy
>
65535
)
return
;
for
(
idx
=
0
;
idx
<
3
;
idx
++
)
memset
(
&
inp
[
idx
],
0
,
sizeof
inp
[
idx
]);
idx
=
0
;
inp
[
idx
].
type
=
INPUT_MOUSE
;
inp
[
idx
].
mi
.
dx
=
normx
;
inp
[
idx
].
mi
.
dy
=
normy
;
inp
[
idx
].
mi
.
dwFlags
=
MOUSEEVENTF_MOVE
|
MOUSEEVENTF_ABSOLUTE
;
idx
++
;
inp
[
idx
].
type
=
INPUT_MOUSE
;
inp
[
idx
].
mi
.
dwFlags
=
MOUSEEVENTF_LEFTDOWN
;
idx
++
;
inp
[
idx
].
type
=
INPUT_MOUSE
;
inp
[
idx
].
mi
.
dwFlags
=
MOUSEEVENTF_LEFTUP
;
idx
++
;
if
(
(
SendInput
(
idx
,
inp
,
sizeof
(
INPUT
))
!=
idx
)
&&
debugfp
)
fprintf
(
debugfp
,
"SendInput failed: %s
\n
"
,
w32_strerror
(
-1
));
#endif
}
/* Resize the button so that STRING fits into it. */
static
void
resize_button
(
HWND
hwnd
,
const
char
*
string
)
{
if
(
!
hwnd
)
return
;
/* FIXME: Need to figure out how to convert dialog coorddnates to
screen coordinates and how buttons should be placed. */
/* SetWindowPos (hbutton, NULL, */
/* 10, 180, */
/* strlen (string+2), 14, */
/* (SWP_NOZORDER)); */
}
/* Call SetDlgItemTextW with an UTF8 string. */
static
void
set_dlg_item_text
(
HWND
dlg
,
int
item
,
const
char
*
string
)
{
if
(
!
string
||
!*
string
)
SetDlgItemTextW
(
dlg
,
item
,
L
""
);
else
{
wchar_t
*
wbuf
;
wbuf
=
utf8_to_wchar
(
string
);
if
(
!
wbuf
)
SetDlgItemTextW
(
dlg
,
item
,
L
"[out of core]"
);
else
{
SetDlgItemTextW
(
dlg
,
item
,
wbuf
);
free
(
wbuf
);
}
}
}
/* Load our butmapped icon from the resource and display it. */
static
void
set_bitmap
(
HWND
dlg
,
int
item
)
{
HWND
hwnd
;
HBITMAP
bitmap
;
RECT
rect
;
int
resid
;
hwnd
=
GetDlgItem
(
dlg
,
item
);
if
(
!
hwnd
)
return
;
rect
.
left
=
0
;
rect
.
top
=
0
;
rect
.
right
=
32
;
rect
.
bottom
=
32
;
if
(
!
MapDialogRect
(
dlg
,
&
rect
))
{
fprintf
(
stderr
,
"MapDialogRect failed: %s
\n
"
,
w32_strerror
(
-1
));
return
;
}
/* fprintf (stderr, "MapDialogRect: %d/%d\n", rect.right, rect.bottom); */
switch
(
rect
.
right
)
{
case
32
:
resid
=
IDB_ICON_32
;
break
;
case
48
:
resid
=
IDB_ICON_48
;
break
;
case
64
:
resid
=
IDB_ICON_64
;
break
;
case
96
:
resid
=
IDB_ICON_96
;
break
;
default
:
resid
=
IDB_ICON_128
;
break
;
}
bitmap
=
LoadImage
(
GetModuleHandle
(
NULL
),
MAKEINTRESOURCE
(
resid
),
IMAGE_BITMAP
,
rect
.
right
,
rect
.
bottom
,
(
LR_SHARED
|
LR_LOADTRANSPARENT
|
LR_LOADMAP3DCOLORS
));
if
(
!
bitmap
)
{
fprintf
(
stderr
,
"LoadImage failed: %s
\n
"
,
w32_strerror
(
-1
));
return
;
}
SendMessage
(
hwnd
,
STM_SETIMAGE
,
(
WPARAM
)
IMAGE_BITMAP
,
(
LPARAM
)
bitmap
);
}
/* Dialog processing loop. */
static
BOOL
CALLBACK
dlg_proc
(
HWND
dlg
,
UINT
msg
,
WPARAM
wparam
,
LPARAM
lparam
)
{
static
pinentry_t
pe
;
/* static int item; */
/* { */
/* int idx; */
/* for (idx=0; msgcodes[idx].string; idx++) */
/* if (msg == msgcodes[idx].msg) */
/* break; */
/* if (msgcodes[idx].string) */
/* fprintf (debugfp, "received %s\n", msgcodes[idx].string); */
/* else */
/* fprintf (debugfp, "received WM_%u\n", msg); */
/* } */
switch
(
msg
)
{
case
WM_INITDIALOG
:
dialog_handle
=
dlg
;
pe
=
(
pinentry_t
)
lparam
;
if
(
!
pe
)
abort
();
set_dlg_item_text
(
dlg
,
IDC_PINENT_PROMPT
,
pe
->
prompt
);
set_dlg_item_text
(
dlg
,
IDC_PINENT_DESC
,
pe
->
description
);
set_dlg_item_text
(
dlg
,
IDC_PINENT_TEXT
,
""
);
set_bitmap
(
dlg
,
IDC_PINENT_ICON
);
if
(
pe
->
ok
)
{
set_dlg_item_text
(
dlg
,
IDOK
,
pe
->
ok
);
resize_button
(
GetDlgItem
(
dlg
,
IDOK
),
pe
->
ok
);
}
if
(
pe
->
cancel
)
{
set_dlg_item_text
(
dlg
,
IDCANCEL
,
pe
->
cancel
);
resize_button
(
GetDlgItem
(
dlg
,
IDCANCEL
),
pe
->
cancel
);
}
if
(
pe
->
error
)
set_dlg_item_text
(
dlg
,
IDC_PINENT_ERR
,
pe
->
error
);
if
(
confirm_mode
)
{
EnableWindow
(
GetDlgItem
(
dlg
,
IDC_PINENT_TEXT
),
FALSE
);
SetWindowPos
(
GetDlgItem
(
dlg
,
IDC_PINENT_TEXT
),
NULL
,
0
,
0
,
0
,
0
,
(
SWP_NOMOVE
|
SWP_NOSIZE
|
SWP_NOZORDER
|
SWP_HIDEWINDOW
));
/* item = IDOK; */
}
/* else */
/* item = IDC_PINENT_TEXT; */
center_window
(
dlg
,
HWND_TOP
);
/* Unfortunately we can't use SetForegroundWindow because there
is no easy eay to have all the calling processes do an
AllowSetForegroundWindow. What we do instead is to bad hack
by simulating a click to the Window. */
/* if (SetForegroundWindow (dlg) && lock_set_foreground_window) */
/* { */
/* lock_set_foreground_window (LSFW_LOCK); */
/* } */
/* show_window_hierarchy (GetDesktopWindow (), 0); */
ShowWindow
(
dlg
,
SW_SHOW
);
move_mouse_and_click
(
GetDlgItem
(
dlg
,
IDC_PINENT_PROMPT
)
);
raise_sip
(
dlg
);
break
;
case
WM_COMMAND
:
switch
(
LOWORD
(
wparam
))
{
case
IDOK
:
if
(
confirm_mode
)
confirm_yes
=
1
;
else
ok_button_clicked
(
dlg
,
pe
);
EndDialog
(
dlg
,
TRUE
);
break
;
case
IDCANCEL
:
pe
->
result
=
-1
;
EndDialog
(
dlg
,
FALSE
);
break
;
}
break
;
case
WM_KEYDOWN
:
if
(
wparam
==
VK_RETURN
)
{
if
(
confirm_mode
)
confirm_yes
=
1
;
else
ok_button_clicked
(
dlg
,
pe
);
EndDialog
(
dlg
,
TRUE
);
}
break
;
case
WM_CTLCOLORSTATIC
:
if
((
HWND
)
lparam
==
GetDlgItem
(
dlg
,
IDC_PINENT_ERR
))
{
/* Display the error prompt in red. */
SetTextColor
((
HDC
)
wparam
,
RGB
(
255
,
0
,
0
));
SetBkMode
((
HDC
)
wparam
,
TRANSPARENT
);
return
(
BOOL
)
GetStockObject
(
NULL_BRUSH
);
}
break
;
}
return
FALSE
;
}
/* The okay button has been clicked or the enter enter key in the text
field. */
static
void
ok_button_clicked
(
HWND
dlg
,
pinentry_t
pe
)
{
char
*
s_utf8
;
wchar_t
*
w_buffer
;
size_t
w_buffer_size
=
255
;
unsigned
int
nchar
;
pe
->
locale_err
=
1
;
w_buffer
=
secmem_malloc
((
w_buffer_size
+
1
)
*
sizeof
*
w_buffer
);
if
(
!
w_buffer
)
return
;
nchar
=
GetDlgItemTextW
(
dlg
,
IDC_PINENT_TEXT
,
w_buffer
,
w_buffer_size
);
s_utf8
=
wchar_to_utf8
(
w_buffer
,
nchar
,
1
);
secmem_free
(
w_buffer
);
if
(
s_utf8
)
{
passphrase_ok
=
1
;
pinentry_setbufferlen
(
pe
,
strlen
(
s_utf8
)
+
1
);
if
(
pe
->
pin
)
strcpy
(
pe
->
pin
,
s_utf8
);
secmem_free
(
s_utf8
);
pe
->
locale_err
=
0
;
pe
->
result
=
pe
->
pin
?
strlen
(
pe
->
pin
)
:
0
;
}
}
static
int
w32_cmd_handler
(
pinentry_t
pe
)
{
/* HWND lastwindow = GetForegroundWindow (); */
confirm_mode
=
!
pe
->
pin
;
passphrase_ok
=
confirm_yes
=
0
;
dialog_handle
=
NULL
;
DialogBoxParam
(
GetModuleHandle
(
NULL
),
MAKEINTRESOURCE
(
IDD_PINENT
),
GetDesktopWindow
(),
dlg_proc
,
(
LPARAM
)
pe
);
if
(
dialog_handle
)
{
/* if (lock_set_foreground_window) */
/* lock_set_foreground_window (LSFW_UNLOCK); */
/* if (lastwindow) */
/* SetForegroundWindow (lastwindow); */
}
else
return
-1
;
if
(
confirm_mode
)
return
confirm_yes
;
else
if
(
passphrase_ok
&&
pe
->
pin
)
return
strlen
(
pe
->
pin
);
else
return
-1
;
}
/* WindowsCE uses a very strange way of handling the standard streams.
There is a function SetStdioPath to associate a standard stream
with a file or a device but what we really want is to use pipes as
standard streams. Despite that we implement pipes using a device,
we would have some limitations on the number of open pipes due to
the 3 character limit of device file name. Thus we don't take this
path. Another option would be to install a file system driver with
support for pipes; this would allow us to get rid of the device
name length limitation. However, with GnuPG we can get away be
redefining the standard streams and passing the handles to be used
on the command line. This has also the advantage that it makes
creating a process much easier and does not require the
SetStdioPath set and restore game. The caller needs to pass the
rendezvous ids using up to three options:
-&S0=<rvid> -&S1=<rvid> -&S2=<rvid>
They are all optional but they must be the first arguments on the
command line. Parsing stops as soon as an invalid option is found.
These rendezvous ids are then used to finish the pipe creation.*/
#ifdef HAVE_W32CE_SYSTEM
static
void
parse_std_file_handles
(
int
*
argcp
,
char
***
argvp
)
{
int
argc
=
*
argcp
;
char
**
argv
=
*
argvp
;
const
char
*
s
;
int
fd
;
int
i
;
int
fixup
=
0
;
if
(
!
argc
)
return
;
for
(
argc
--
,
argv
++
;
argc
;
argc
--
,
argv
++
)
{
s
=
*
argv
;
if
(
*
s
==
'-'
&&
s
[
1
]
==
'&'
&&
s
[
2
]
==
'S'
&&
(
s
[
3
]
==
'0'
||
s
[
3
]
==
'1'
||
s
[
3
]
==
'2'
)
&&
s
[
4
]
==
'='
&&
(
strchr
(
"-01234567890"
,
s
[
5
])
||
!
strcmp
(
s
+
5
,
"null"
)))
{
if
(
s
[
5
]
==
'n'
)
fd
=
(
int
)(
-1
);
else
fd
=
(
int
)
w32ce_finish_pipe
(
atoi
(
s
+
5
),
s
[
3
]
!=
'0'
);
if
(
s
[
3
]
==
'0'
&&
fd
!=
-1
)
w32_infd
=
fd
;
else
if
(
s
[
3
]
==
'1'
&&
fd
!=
-1
)
w32_outfd
=
fd
;
fixup
++
;
}
else
break
;
}
if
(
fixup
)
{
argc
=
*
argcp
;
argc
-=
fixup
;
*
argcp
=
argc
;
argv
=
*
argvp
;
for
(
i
=
1
;
i
<
argc
;
i
++
)
argv
[
i
]
=
argv
[
i
+
fixup
];
for
(;
i
<
argc
+
fixup
;
i
++
)
argv
[
i
]
=
NULL
;
}
}
#endif
/*HAVE_W32CE_SYSTEM*/
int
main
(
int
argc
,
char
**
argv
)
{
#ifndef HAVE_W32CE_SYSTEM
void
*
handle
;
#endif
w32_infd
=
STDIN_FILENO
;
w32_outfd
=
STDOUT_FILENO
;
#ifdef HAVE_W32CE_SYSTEM
parse_std_file_handles
(
&
argc
,
&
argv
);
#endif
pinentry_init
(
PGMNAME
);
pinentry_parse_opts
(
argc
,
argv
);
/* debugfp = fopen ("pinentry.log", "w"); */
/* if (!debugfp) */
/* debugfp = stderr; */
/* We need to load a function because that one is only available
since W2000 but not in older NTs. */
#ifndef HAVE_W32CE_SYSTEM
handle
=
LoadLibrary
(
"user32.dll"
);
if
(
handle
)
{
void
*
foo
;
foo
=
GetProcAddress
(
handle
,
"LockSetForegroundWindow"
);
if
(
foo
)
lock_set_foreground_window
=
foo
;
else
CloseHandle
(
handle
);
}
#endif
if
(
pinentry_loop2
(
w32_infd
,
w32_outfd
))
return
1
;
#ifdef HAVE_W32CE_SYSTEM
Sleep
(
400
);
#endif
return
0
;
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Thu, Feb 26, 6:27 PM (14 h, 41 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
5b/b0/57365c62cd28e0be9f376e58d6ae
Attached To
rP Pinentry
Event Timeline
Log In to Comment