1 /* Win32API/File.xs */
2 
3 #include "EXTERN.h"
4 #include "perl.h"
5 #include "XSUB.h"
6 /*#include "patchlevel.h"*/
7 
8 /* Uncomment the next line unless set "WRITE_PERL=>1" in Makefile.PL: */
9 #define NEED_newCONSTSUB
10 #include "ppport.h"
11 
12 #ifdef WORD
13 # undef WORD
14 #endif
15 
16 #define  WIN32_LEAN_AND_MEAN	/* Tell windows.h to skip much */
17 #include <windows.h>
18 #include <winioctl.h>
19 
20 /*CONSTS_DEFINED*/
21 
22 #ifndef INVALID_SET_FILE_POINTER
23 #   define INVALID_SET_FILE_POINTER	((DWORD)-1)
24 #endif
25 
26 #define oDWORD DWORD
27 
28 #if (PERL_REVISION <= 5 && PERL_VERSION < 5) || defined(__CYGWIN__)
29 # define win32_get_osfhandle _get_osfhandle
30 # ifdef __CYGWIN__
31 #  define win32_open_osfhandle(handle,mode) \
32 	(Perl_croak(aTHX_ "_open_osfhandle not implemented on Cygwin!"), -1)
33 # else
34 #  define win32_open_osfhandle _open_osfhandle
35 # endif
36 # ifdef _get_osfhandle
37 #  undef _get_osfhandle	/* stolen_get_osfhandle() isn't available here */
38 # endif
39 # ifdef _open_osfhandle
40 #  undef _open_osfhandle /* stolen_open_osfhandle() isn't available here */
41 # endif
42 #endif
43 
44 #ifndef XST_mUV
45 # define XST_mUV(i,v)  (ST(i) = sv_2mortal(newSVuv(v))  )
46 #endif
47 
48 #ifndef XSRETURN_UV
49 # define XSRETURN_UV(v) STMT_START { XST_mUV(0,v);  XSRETURN(1); } STMT_END
50 #endif
51 
52 #ifndef DEBUGGING
53 # define	Debug(list)	/*Nothing*/
54 #else
55 # define	Debug(list)	ErrPrintf list
56 # include <stdarg.h>
57     static void
58     ErrPrintf( const char *sFmt, ... )
59     {
60       va_list pAList;
61       static char *sEnv= NULL;
62       DWORD uErr= GetLastError();
63 	if(  NULL == sEnv  ) {
64 	    if(  NULL == ( sEnv= getenv("DEBUG_WIN32API_FILE") )  )
65 		sEnv= "";
66 	}
67 	if(  '\0' == *sEnv  )
68 	    return;
69 	va_start( pAList, sFmt );
70 	vfprintf( stderr, sFmt, pAList );
71 	va_end( pAList );
72 	SetLastError( uErr );
73     }
74 #endif /* DEBUGGING */
75 
76 
77 #include "buffers.h"	/* Include this after DEBUGGING setup finished */
78 
79 static LONG uLastFileErr= 0;
80 
81 static void
82 SaveErr( BOOL bFailed )
83 {
84     if(  bFailed  ) {
85 	uLastFileErr= GetLastError();
86     }
87 }
88 
89 MODULE = Win32API::File		PACKAGE = Win32API::File
90 
91 PROTOTYPES: DISABLE
92 
93 
94 LONG
95 _fileLastError( uError=0 )
96 	DWORD	uError
97     CODE:
98 	if(  1 <= items  ) {
99 	    uLastFileErr= uError;
100 	}
101 	RETVAL= uLastFileErr;
102     OUTPUT:
103 	RETVAL
104 
105 
106 BOOL
107 CloseHandle( hObject )
108 	HANDLE	hObject
109     CODE:
110         RETVAL = CloseHandle( hObject );
111 	SaveErr( !RETVAL );
112     OUTPUT:
113 	RETVAL
114 
115 
116 BOOL
117 CopyFileA( sOldFileName, sNewFileName, bFailIfExists )
118 	char *	sOldFileName
119 	char *	sNewFileName
120 	BOOL	bFailIfExists
121     CODE:
122         RETVAL = CopyFileA( sOldFileName, sNewFileName, bFailIfExists );
123 	SaveErr( !RETVAL );
124     OUTPUT:
125 	RETVAL
126 
127 
128 BOOL
129 CopyFileW( swOldFileName, swNewFileName, bFailIfExists )
130 	WCHAR *	swOldFileName
131 	WCHAR *	swNewFileName
132 	BOOL	bFailIfExists
133     CODE:
134         RETVAL = CopyFileW( swOldFileName, swNewFileName, bFailIfExists );
135 	SaveErr( !RETVAL );
136     OUTPUT:
137 	RETVAL
138 
139 
140 HANDLE
141 CreateFileA( sPath, uAccess, uShare, pSecAttr, uCreate, uFlags, hModel )
142 	char *	sPath
143 	DWORD	uAccess
144 	DWORD	uShare
145 	void *	pSecAttr
146 	DWORD	uCreate
147 	DWORD	uFlags
148 	HANDLE	hModel
149     CODE:
150 	RETVAL= CreateFileA( sPath, uAccess, uShare,
151 	  (LPSECURITY_ATTRIBUTES)pSecAttr, uCreate, uFlags, hModel );
152 	if(  INVALID_HANDLE_VALUE == RETVAL  ) {
153 	    SaveErr( 1 );
154 	    XSRETURN_NO;
155 	} else if(  0 == RETVAL  ) {
156 	    XSRETURN_PV( "0 but true" );
157 	} else {
158 	    XSRETURN_UV( PTR2UV(RETVAL) );
159 	}
160 
161 
162 HANDLE
163 CreateFileW( swPath, uAccess, uShare, pSecAttr, uCreate, uFlags, hModel )
164 	WCHAR *	swPath
165 	DWORD	uAccess
166 	DWORD	uShare
167 	void *	pSecAttr
168 	DWORD	uCreate
169 	DWORD	uFlags
170 	HANDLE	hModel
171     CODE:
172 	RETVAL= CreateFileW( swPath, uAccess, uShare,
173 	  (LPSECURITY_ATTRIBUTES)pSecAttr, uCreate, uFlags, hModel );
174 	if(  INVALID_HANDLE_VALUE == RETVAL  ) {
175 	    SaveErr( 1 );
176 	    XSRETURN_NO;
177 	} else if(  0 == RETVAL  ) {
178 	    XSRETURN_PV( "0 but true" );
179 	} else {
180 	    XSRETURN_UV( PTR2UV(RETVAL) );
181 	}
182 
183 
184 BOOL
185 DefineDosDeviceA( uFlags, sDosDeviceName, sTargetPath )
186 	DWORD	uFlags
187 	char *	sDosDeviceName
188 	char *	sTargetPath
189     CODE:
190         RETVAL = DefineDosDeviceA( uFlags, sDosDeviceName, sTargetPath );
191 	SaveErr( !RETVAL );
192     OUTPUT:
193 	RETVAL
194 
195 
196 BOOL
197 DefineDosDeviceW( uFlags, swDosDeviceName, swTargetPath )
198 	DWORD	uFlags
199 	WCHAR *	swDosDeviceName
200 	WCHAR *	swTargetPath
201     CODE:
202         RETVAL = DefineDosDeviceW( uFlags, swDosDeviceName, swTargetPath );
203 	SaveErr( !RETVAL );
204     OUTPUT:
205 	RETVAL
206 
207 
208 BOOL
209 DeleteFileA( sFileName )
210 	char *	sFileName
211     CODE:
212         RETVAL = DeleteFileA( sFileName );
213 	SaveErr( !RETVAL );
214     OUTPUT:
215 	RETVAL
216 
217 
218 BOOL
219 DeleteFileW( swFileName )
220 	WCHAR *	swFileName
221     CODE:
222         RETVAL = DeleteFileW( swFileName );
223 	SaveErr( !RETVAL );
224     OUTPUT:
225 	RETVAL
226 
227 
228 BOOL
229 DeviceIoControl( hDevice, uIoControlCode, pInBuf, lInBuf, opOutBuf, lOutBuf, olRetBytes, pOverlapped )
230 	HANDLE	hDevice
231 	DWORD	uIoControlCode
232 	char *	pInBuf
233 	DWORD	lInBuf		= init_buf_l($arg);
234 	char *	opOutBuf	= NO_INIT
235 	DWORD	lOutBuf		= init_buf_l($arg);
236 	oDWORD	&olRetBytes
237 	void *	pOverlapped
238     CODE:
239 	if(  NULL != pInBuf  ) {
240 	    if(  0 == lInBuf  ) {
241 		lInBuf= SvCUR(ST(2));
242 	    } else if(  SvCUR(ST(2)) < lInBuf  ) {
243 		croak( "%s: pInBuf shorter than specified (%d < %d)",
244 		  "Win32API::File::DeviceIoControl", SvCUR(ST(2)), lInBuf );
245 	    }
246 	}
247 	grow_buf_l( opOutBuf,ST(4),char *, lOutBuf,ST(5) );
248 	RETVAL= DeviceIoControl( hDevice, uIoControlCode, pInBuf, lInBuf,
249 		  opOutBuf, lOutBuf, &olRetBytes, (LPOVERLAPPED)pOverlapped );
250 	SaveErr( !RETVAL );
251     OUTPUT:
252 	RETVAL
253 	opOutBuf	trunc_buf_l( RETVAL, opOutBuf,ST(4), olRetBytes );
254 	olRetBytes
255 
256 
257 HANDLE
258 FdGetOsFHandle( ivFd )
259 	int	ivFd
260     CODE:
261 	RETVAL= (HANDLE) win32_get_osfhandle( ivFd );
262 	SaveErr( INVALID_HANDLE_VALUE == RETVAL );
263     OUTPUT:
264 	RETVAL
265 
266 
267 DWORD
268 GetDriveTypeA( sRootPath )
269 	char *	sRootPath
270     CODE:
271         RETVAL = GetDriveTypeA( sRootPath );
272 	SaveErr( !RETVAL );
273     OUTPUT:
274 	RETVAL
275 
276 
277 DWORD
278 GetDriveTypeW( swRootPath )
279 	WCHAR *	swRootPath
280     CODE:
281         RETVAL = GetDriveTypeW( swRootPath );
282 	SaveErr( !RETVAL );
283     OUTPUT:
284 	RETVAL
285 
286 
287 DWORD
288 GetFileAttributesA( sPath )
289 	char *	sPath
290     CODE:
291         RETVAL = GetFileAttributesA( sPath );
292 	SaveErr( !RETVAL );
293     OUTPUT:
294 	RETVAL
295 
296 
297 DWORD
298 GetFileAttributesW( swPath )
299 	WCHAR *	swPath
300     CODE:
301         RETVAL = GetFileAttributesW( swPath );
302 	SaveErr( !RETVAL );
303     OUTPUT:
304 	RETVAL
305 
306 
307 DWORD
308 GetFileType( hFile )
309 	HANDLE	hFile
310     CODE:
311         RETVAL = GetFileType( hFile );
312 	SaveErr( !RETVAL );
313     OUTPUT:
314 	RETVAL
315 
316 
317 BOOL
318 GetHandleInformation( hObject, ouFlags )
319 	HANDLE		hObject
320 	oDWORD *	ouFlags
321     CODE:
322         RETVAL = GetHandleInformation( hObject, ouFlags );
323 	SaveErr( !RETVAL );
324     OUTPUT:
325 	RETVAL
326 	ouFlags
327 
328 
329 DWORD
330 GetLogicalDrives()
331     CODE:
332         RETVAL = GetLogicalDrives();
333 	SaveErr( !RETVAL );
334     OUTPUT:
335 	RETVAL
336 
337 
338 DWORD
339 GetLogicalDriveStringsA( lBufSize, osBuffer )
340 	DWORD	lBufSize	= init_buf_l($arg);
341 	char *	osBuffer	= NO_INIT
342     CODE:
343 	grow_buf_l( osBuffer,ST(1),char *, lBufSize,ST(0) );
344 	RETVAL= GetLogicalDriveStringsA( lBufSize, osBuffer );
345 	if(  lBufSize < RETVAL  &&  autosize(ST(0))  ) {
346 	    lBufSize= RETVAL;
347 	    grow_buf_l( osBuffer,ST(1),char *, lBufSize,ST(0) );
348 	    RETVAL= GetLogicalDriveStringsA( lBufSize, osBuffer );
349 	}
350 	if(  0 == RETVAL  ||  lBufSize < RETVAL  ) {
351 	    SaveErr( 1 );
352 	} else {
353 	    trunc_buf_l( 1, osBuffer,ST(1), RETVAL );
354 	}
355     OUTPUT:
356 	RETVAL
357 	osBuffer	;/* The code for this appears above. */
358 
359 
360 DWORD
361 GetLogicalDriveStringsW( lwBufSize, oswBuffer )
362 	DWORD	lwBufSize	= init_buf_lw($arg);
363 	WCHAR *	oswBuffer	= NO_INIT
364     CODE:
365 	grow_buf_lw( oswBuffer,ST(1), lwBufSize,ST(0) );
366 	RETVAL= GetLogicalDriveStringsW( lwBufSize, oswBuffer );
367 	if(  lwBufSize < RETVAL  &&  autosize(ST(0))  ) {
368 	    lwBufSize= RETVAL;
369 	    grow_buf_lw( oswBuffer,ST(1), lwBufSize,ST(0) );
370 	    RETVAL= GetLogicalDriveStringsW( lwBufSize, oswBuffer );
371 	}
372 	if(  0 == RETVAL  ||  lwBufSize < RETVAL  ) {
373 	    SaveErr( 1 );
374 	} else {
375 	    trunc_buf_lw( 1, oswBuffer,ST(1), RETVAL );
376 	}
377     OUTPUT:
378 	RETVAL
379 	oswBuffer	;/* The code for this appears above. */
380 
381 
382 BOOL
383 GetVolumeInformationA( sRootPath, osVolName, lVolName, ouSerialNum, ouMaxNameLen, ouFsFlags, osFsType, lFsType )
384 	char *	sRootPath
385 	char *	osVolName	= NO_INIT
386 	DWORD	lVolName	= init_buf_l($arg);
387 	oDWORD	&ouSerialNum	= optUV($arg);
388 	oDWORD	&ouMaxNameLen	= optUV($arg);
389 	oDWORD	&ouFsFlags	= optUV($arg);
390 	char *	osFsType	= NO_INIT
391 	DWORD	lFsType		= init_buf_l($arg);
392     CODE:
393 	grow_buf_l( osVolName,ST(1),char *, lVolName,ST(2) );
394 	grow_buf_l( osFsType,ST(6),char *, lFsType,ST(7) );
395 	RETVAL= GetVolumeInformationA( sRootPath, osVolName, lVolName,
396 		  &ouSerialNum, &ouMaxNameLen, &ouFsFlags, osFsType, lFsType );
397 	SaveErr( !RETVAL );
398     OUTPUT:
399 	RETVAL
400 	osVolName	trunc_buf_z( RETVAL, osVolName,ST(1) );
401 	osFsType	trunc_buf_z( RETVAL, osFsType,ST(6) );
402 	ouSerialNum
403 	ouMaxNameLen
404 	ouFsFlags
405 
406 
407 BOOL
408 GetVolumeInformationW( swRootPath, oswVolName, lwVolName, ouSerialNum, ouMaxNameLen, ouFsFlags, oswFsType, lwFsType )
409 	WCHAR *	swRootPath
410 	WCHAR *	oswVolName	= NO_INIT
411 	DWORD	lwVolName	= init_buf_lw($arg);
412 	oDWORD	&ouSerialNum	= optUV($arg);
413 	oDWORD	&ouMaxNameLen	= optUV($arg);
414 	oDWORD	&ouFsFlags	= optUV($arg);
415 	WCHAR *	oswFsType	= NO_INIT
416 	DWORD	lwFsType	= init_buf_lw($arg);
417     CODE:
418 	grow_buf_lw( oswVolName,ST(1), lwVolName,ST(2) );
419 	grow_buf_lw( oswFsType,ST(6), lwFsType,ST(7) );
420 	RETVAL= GetVolumeInformationW( swRootPath, oswVolName, lwVolName,
421 	  &ouSerialNum, &ouMaxNameLen, &ouFsFlags, oswFsType, lwFsType );
422 	SaveErr( !RETVAL );
423     OUTPUT:
424 	RETVAL
425 	oswVolName	trunc_buf_zw( RETVAL, oswVolName,ST(1) );
426 	oswFsType	trunc_buf_zw( RETVAL, oswFsType,ST(6) );
427 	ouSerialNum
428 	ouMaxNameLen
429 	ouFsFlags
430 
431 
432 BOOL
433 IsRecognizedPartition( ivPartitionType )
434 	int	ivPartitionType
435     CODE:
436         RETVAL = IsRecognizedPartition( ivPartitionType );
437 	SaveErr( !RETVAL );
438     OUTPUT:
439 	RETVAL
440 
441 
442 BOOL
443 IsContainerPartition( ivPartitionType )
444 	int	ivPartitionType
445     CODE:
446         RETVAL = IsContainerPartition( ivPartitionType );
447 	SaveErr( !RETVAL );
448     OUTPUT:
449 	RETVAL
450 
451 
452 BOOL
453 MoveFileA( sOldName, sNewName )
454 	char *	sOldName
455 	char *	sNewName
456     CODE:
457         RETVAL = MoveFileA( sOldName, sNewName );
458 	SaveErr( !RETVAL );
459     OUTPUT:
460 	RETVAL
461 
462 
463 BOOL
464 MoveFileW( swOldName, swNewName )
465 	WCHAR *	swOldName
466 	WCHAR *	swNewName
467     CODE:
468         RETVAL = MoveFileW( swOldName, swNewName );
469 	SaveErr( !RETVAL );
470     OUTPUT:
471 	RETVAL
472 
473 
474 BOOL
475 MoveFileExA( sOldName, sNewName, uFlags )
476 	char *	sOldName
477 	char *	sNewName
478 	DWORD	uFlags
479     CODE:
480         RETVAL = MoveFileExA( sOldName, sNewName, uFlags );
481 	SaveErr( !RETVAL );
482     OUTPUT:
483 	RETVAL
484 
485 
486 BOOL
487 MoveFileExW( swOldName, swNewName, uFlags )
488 	WCHAR *	swOldName
489 	WCHAR *	swNewName
490 	DWORD	uFlags
491     CODE:
492         RETVAL = MoveFileExW( swOldName, swNewName, uFlags );
493 	SaveErr( !RETVAL );
494     OUTPUT:
495 	RETVAL
496 
497 
498 long
499 OsFHandleOpenFd( hOsFHandle, uMode )
500 	long	hOsFHandle
501 	DWORD	uMode
502     CODE:
503 	RETVAL= win32_open_osfhandle( hOsFHandle, uMode );
504 	if(  RETVAL < 0  ) {
505 	    SaveErr( 1 );
506 	    XSRETURN_NO;
507 	} else if(  0 == RETVAL  ) {
508 	    XSRETURN_PV( "0 but true" );
509 	} else {
510 	    XSRETURN_IV( (IV) RETVAL );
511 	}
512 
513 
514 DWORD
515 QueryDosDeviceA( sDeviceName, osTargetPath, lTargetBuf )
516 	char *	sDeviceName
517 	char *	osTargetPath	= NO_INIT
518 	DWORD	lTargetBuf	= init_buf_l($arg);
519     CODE:
520 	grow_buf_l( osTargetPath,ST(1),char *, lTargetBuf,ST(2) );
521 	RETVAL= QueryDosDeviceA( sDeviceName, osTargetPath, lTargetBuf );
522 	SaveErr( 0 == RETVAL );
523     OUTPUT:
524 	RETVAL
525 	osTargetPath	trunc_buf_l( 1, osTargetPath,ST(1), RETVAL );
526 
527 
528 DWORD
529 QueryDosDeviceW( swDeviceName, oswTargetPath, lwTargetBuf )
530 	WCHAR *	swDeviceName
531 	WCHAR *	oswTargetPath	= NO_INIT
532 	DWORD	lwTargetBuf	= init_buf_lw($arg);
533     CODE:
534 	grow_buf_lw( oswTargetPath,ST(1), lwTargetBuf,ST(2) );
535 	RETVAL= QueryDosDeviceW( swDeviceName, oswTargetPath, lwTargetBuf );
536 	SaveErr( 0 == RETVAL );
537     OUTPUT:
538 	RETVAL
539 	oswTargetPath	trunc_buf_lw( 1, oswTargetPath,ST(1), RETVAL );
540 
541 
542 BOOL
543 ReadFile( hFile, opBuffer, lBytes, olBytesRead, pOverlapped )
544 	HANDLE	hFile
545 	BYTE *	opBuffer	= NO_INIT
546 	DWORD	lBytes		= init_buf_l($arg);
547 	oDWORD	&olBytesRead
548 	void *	pOverlapped
549     CODE:
550 	grow_buf_l( opBuffer,ST(1),BYTE *, lBytes,ST(2) );
551 	/* Don't read more bytes than asked for if buffer is already big: */
552 	lBytes= init_buf_l(ST(2));
553 	if(  0 == lBytes  &&  autosize(ST(2))  ) {
554 	    lBytes= SvLEN( ST(1) ) - 1;
555 	}
556 	RETVAL= ReadFile( hFile, opBuffer, lBytes, &olBytesRead,
557 		  (LPOVERLAPPED)pOverlapped );
558 	SaveErr( !RETVAL );
559     OUTPUT:
560 	RETVAL
561 	opBuffer	trunc_buf_l( RETVAL, opBuffer,ST(1), olBytesRead );
562 	olBytesRead
563 
564 
565 BOOL
566 GetOverlappedResult( hFile, lpOverlapped, lpNumberOfBytesTransferred, bWait)
567 	HANDLE hFile
568 	LPOVERLAPPED lpOverlapped
569 	LPDWORD lpNumberOfBytesTransferred
570 	BOOL bWait
571     CODE:
572     	RETVAL= GetOverlappedResult( hFile, lpOverlapped,
573 	 lpNumberOfBytesTransferred, bWait);
574 	SaveErr( !RETVAL );
575     OUTPUT:
576     	RETVAL
577 	lpOverlapped
578 	lpNumberOfBytesTransferred
579 
580 DWORD
581 GetFileSize( hFile, lpFileSizeHigh )
582 	HANDLE hFile
583 	LPDWORD lpFileSizeHigh
584     CODE:
585     	RETVAL= GetFileSize( hFile, lpFileSizeHigh );
586 	SaveErr( NO_ERROR != GetLastError() );
587     OUTPUT:
588     	RETVAL
589 	lpFileSizeHigh
590 
591 UINT
592 SetErrorMode( uNewMode )
593 	UINT	uNewMode
594 
595 
596 LONG
597 SetFilePointer( hFile, ivOffset, ioivOffsetHigh, uFromWhere )
598 	HANDLE	hFile
599 	LONG	ivOffset
600 	LONG *	ioivOffsetHigh
601 	DWORD	uFromWhere
602     CODE:
603 	RETVAL= SetFilePointer( hFile, ivOffset, ioivOffsetHigh, uFromWhere );
604 	if(  RETVAL == INVALID_SET_FILE_POINTER && (GetLastError() != NO_ERROR)  ) {
605 	    SaveErr( 1 );
606 	    XST_mNO(0);
607 	} else if(  0 == RETVAL  ) {
608 	    XST_mPV(0,"0 but true");
609 	} else {
610 	    XST_mIV(0,RETVAL);
611 	}
612     OUTPUT:
613 	ioivOffsetHigh
614 
615 
616 BOOL
617 SetHandleInformation( hObject, uMask, uFlags )
618 	HANDLE	hObject
619 	DWORD	uMask
620 	DWORD	uFlags
621     CODE:
622         RETVAL = SetHandleInformation( hObject, uMask, uFlags );
623 	SaveErr( !RETVAL );
624     OUTPUT:
625 	RETVAL
626 
627 
628 BOOL
629 WriteFile( hFile, pBuffer, lBytes, ouBytesWritten, pOverlapped )
630 	HANDLE		hFile
631 	BYTE *		pBuffer
632 	DWORD		lBytes		= init_buf_l($arg);
633 	oDWORD	&ouBytesWritten
634 	void *		pOverlapped
635     CODE:
636 	/* SvCUR(ST(1)) might "panic" if pBuffer isn't valid */
637 	if(  0 == lBytes  ) {
638 	    lBytes= SvCUR(ST(1));
639 	} else if(  SvCUR(ST(1)) < lBytes  ) {
640 	    croak( "%s: pBuffer value too short (%d < %d)",
641 	      "Win32API::File::WriteFile", SvCUR(ST(1)), lBytes );
642 	}
643 	RETVAL= WriteFile( hFile, pBuffer, lBytes,
644 		  &ouBytesWritten, (LPOVERLAPPED)pOverlapped );
645 	SaveErr( !RETVAL );
646     OUTPUT:
647 	RETVAL
648 	ouBytesWritten
649 
650 void
651 GetStdHandle(fd)
652     DWORD fd
653 PPCODE:
654 #ifdef _WIN64
655     XSRETURN_IV((DWORD_PTR)GetStdHandle(fd));
656 #else
657     XSRETURN_IV((DWORD)GetStdHandle(fd));
658 #endif
659 
660 void
661 SetStdHandle(fd,handle)
662     DWORD fd
663     HANDLE handle
664 PPCODE:
665     if (SetStdHandle(fd, handle))
666 	XSRETURN_YES;
667     else
668 	XSRETURN_NO;
669