1 /*
2 % Copyright (C) 2003 - 2019 GraphicsMagick Group
3 % Copyright (C) 2002 ImageMagick Studio
4 %
5 % This program is covered by multiple licenses, which are described in
6 % Copyright.txt. You should have received a copy of Copyright.txt with this
7 % package; otherwise see http://www.graphicsmagick.org/www/Copyright.html.
8 %
9 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10 % %
11 % %
12 % %
13 % N N TTTTT %
14 % NN N T %
15 % N N N T %
16 % N NN T %
17 % N N T %
18 % %
19 % %
20 % Windows NT Utility Methods for GraphicsMagick %
21 % %
22 % %
23 % Software Design %
24 % John Cristy %
25 % December 1996 %
26 % %
27 % %
28 % %
29 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
30 %
31 %
32 */
33
34 #include "magick/studio.h"
35 #if defined(MSWINDOWS)
36 /*
37 Include declarations.
38 */
39 #include <sys/types.h>
40 #include <sys/utime.h>
41 #include "magick/log.h"
42 #include "magick/magick.h"
43 #include "magick/utility.h"
44 #include "magick/version.h"
45 #if defined(HasLTDL)
46 # include "ltdl.h"
47 #endif /* defined(HasLTDL) */
48 #include "magick/nt_base.h"
49
50 /*
51 Static declarations.
52 */
53 #if !defined(HasLTDL)
54 static char
55 *NTslsearchpath = (char *) NULL;
56 #endif
57 #if defined(HasGS)
58 static void
59 *gs_dll_handle = (void *)NULL;
60 static GhostscriptVectors
61 gs_vectors;
62 #endif /* if defined(HasGS) */
63
64 static MagickPassFail NTstrerror_r(LONG errnum, char *strerrbuf, size_t buflen);
65
66 /*
67 External declarations.
68 */
69 #if !defined(MSWINDOWS)
70 extern "C" BOOL WINAPI
71 DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved);
72 #endif
73
74 static const struct
75 {
76 const HKEY hkey;
77 const char *name;
78 }
79 hkeys[2] =
80 {
81 { HKEY_CURRENT_USER, "HKEY_CURRENT_USER" },
82 { HKEY_LOCAL_MACHINE, "HKEY_LOCAL_MACHINE" }
83 };
84
85
86
87 /*
88 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
89 % %
90 % %
91 % %
92 % N T c l o s e d i r %
93 % %
94 % %
95 % %
96 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
97 %
98 % Method NTclosedir closes the named directory stream and frees the DIR
99 % structure.
100 %
101 % The format of the NTclosedir method is:
102 %
103 % void NTclosedir(DIR *entry)
104 %
105 % A description of each parameter follows:
106 %
107 % o entry: Specifies a pointer to a DIR structure.
108 %
109 %
110 */
NTclosedir(DIR * entry)111 MagickExport int NTclosedir(DIR *entry)
112 {
113 assert(entry != (DIR *) NULL);
114 FindClose(entry->hSearch);
115 MagickFreeMemory(entry);
116 return 0;
117 }
118
119 /*
120 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
121 % %
122 % %
123 % %
124 % DllMain %
125 % %
126 % %
127 % %
128 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
129 %
130 % Method DllMain is an entry point to the DLL which is called when processes
131 % and threads are initialized and terminated, or upon calls to the
132 % Windows LoadLibrary and FreeLibrary functions.
133 %
134 % The function returns TRUE of it succeeds, or FALSE if initialization fails.
135 %
136 % The format of the DllMain method is:
137 %
138 % BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)
139 %
140 % A description of each parameter follows:
141 %
142 % o hinstDLL: handle to the DLL module
143 %
144 % o fdwReason: reason for calling function.
145 %
146 % May have values:
147 % DLL_PROCESS_ATTACH - DLL is being loaded into virtual address
148 % space of current process.
149 % DLL_THREAD_ATTACH - Indicates that the current process is
150 % creating a new thread. Called under the
151 % context of the new thread.
152 % DLL_THREAD_DETACH - Indicates that the thread is exiting.
153 % Called under the context of the exiting
154 % thread.
155 % DLL_PROCESS_DETACH - Indicates that the DLL is being unloaded
156 % from the virtual address space of the
157 % current process.
158 %
159 % o lpvReserved: Used for passing additional info during DLL_PROCESS_ATTACH
160 % and DLL_PROCESS_DETACH.
161 %
162 */
163 #if defined(_DLL) && defined( ProvideDllMain )
DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)164 BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)
165 {
166 switch ( fdwReason )
167 {
168 case DLL_PROCESS_ATTACH:
169 {
170 #define ENV_VAR_MAX 32767 /* environment variable max is 32,767 bytes */
171 #define DLL_PATH_MAX 1024
172
173 char
174 dll_path[DLL_PATH_MAX],
175 current_path[ENV_VAR_MAX];
176
177 long count;
178
179 count = GetModuleFileName(hinstDLL,dll_path,DLL_PATH_MAX);
180 if (count) {
181 for ( ; count>0 ; --count)
182 {
183 if (dll_path[count]=='\\')
184 {
185 dll_path[count+1]='\0';
186 break;
187 }
188 }
189 InitializeMagick(dll_path);
190 count = GetEnvironmentVariable("PATH",current_path,ENV_VAR_MAX);
191 if (strstr(current_path,dll_path) == NULL)
192 {
193 if (strlen(dll_path)+count+1 < ENV_VAR_MAX-1)
194 {
195 char
196 new_path[ENV_VAR_MAX];
197
198 FormatString(new_path,"%.*s;%.*s",DLL_PATH_MAX,dll_path,
199 ENV_VAR_MAX-DLL_PATH_MAX-1,current_path);
200 SetEnvironmentVariable("PATH",new_path);
201 }
202 }
203 break;
204 }
205 /* If we get here, then GetModuleFileName must have failed */
206 return FALSE;
207 break;
208 }
209 case DLL_PROCESS_DETACH:
210 DestroyMagick();
211 break;
212 default:
213 {
214 /* Do nothing */
215 }
216 }
217 return TRUE;
218 }
219 #endif
220
221 /*
222 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
223 % %
224 % %
225 % %
226 % E x i t %
227 % %
228 % %
229 % %
230 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
231 %
232 % Method Exit calls TerminateProcess for Win95. Should quit the program
233 % and not return.
234 %
235 % The format of the Exit method is:
236 %
237 % void Exit(int status)
238 %
239 % A description of each parameter follows:
240 %
241 % o status: an integer value representing the status of the terminating
242 % process.
243 %
244 %
245 */
Exit(int status)246 MagickExport void Exit(int status)
247 {
248 if (IsWindows95())
249 TerminateProcess(GetCurrentProcess(),(unsigned int) status);
250 exit(status);
251 }
252
253 /*
254 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
255 % %
256 % %
257 % %
258 % M a g i c k G e t M M U P a g e S i z e %
259 % %
260 % %
261 % %
262 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
263 %
264 % MagickGetMMUPageSize() returns the VM pagesize used by the MMU. The VM
265 % pagesize is the number of bytes retrieved due to one page fault.
266 %
267 % The format of the MagickGetMMUPageSize method is:
268 %
269 % long MagickGetMMUPageSize()
270 %
271 */
MagickGetMMUPageSize()272 MagickExport long MagickGetMMUPageSize()
273 {
274 return 4096;
275 }
276
277 /*
278 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
279 % %
280 % %
281 % %
282 % M a g i c k G e t F i l e A t t r i b u t e s %
283 % %
284 % %
285 % %
286 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
287 %
288 % MagickGetFileAttributes() returns the file attributes for a specified
289 % file in a structure of type MagickStatStruct_t.
290 %
291 % The format of the MagickGetFileAttributes method is:
292 %
293 % int MagickGetFileAttributes(const char *filename,
294 % MagickStatStruct_t *statbuf)
295 %
296 % A description of each parameter follows:
297 %
298 % o filename: Path to the file
299 %
300 % o statbuf: A structure of type MagickStatStruct_t to populate.
301 %
302 %
303 */
MagickGetFileAttributes(const char * filename,MagickStatStruct_t * statbuf)304 MagickExport int MagickGetFileAttributes(const char *filename,
305 MagickStatStruct_t *statbuf)
306 {
307 if (MagickStat(filename, statbuf) != 0)
308 return -1;
309
310 return 0;
311 }
312
313 /*
314 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
315 % %
316 % %
317 % %
318 % M a g i c k S e t F i l e A t t r i b u t e s %
319 % %
320 % %
321 % %
322 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
323 %
324 % MagickSetFileAttributes() sets the access and modification time file
325 % attributes based on values provided via in a structure of type
326 % MagickStatStruct_t.
327 %
328 % The format of the MagickGetFileAttributes method is:
329 %
330 % int MagickSetFileAttributes(const char *filename,
331 % const MagickStatStruct_t *statbuf)
332 %
333 % A description of each parameter follows:
334 %
335 % o filename: Path to the file
336 %
337 % o statbuf: A structure of type MagickStatStruct_t to populate.
338 %
339 %
340 */
MagickSetFileAttributes(const char * filename,const MagickStatStruct_t * statbuf)341 MagickExport int MagickSetFileAttributes(const char *filename,
342 const MagickStatStruct_t *statbuf)
343 {
344 /*
345 Setting file timestamps on Windows is actually almost the same as on POSIX systems.
346 https://msdn.microsoft.com/en-us/library/4wacf567.aspx
347 */
348 struct _utimbuf
349 ut;
350
351 ut.actime = statbuf->st_atime;
352 ut.modtime = statbuf->st_mtime;
353
354 if (_utime(filename, &ut) == -1)
355 return -1;
356
357 return 0;
358 }
359
360 /*
361 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
362 % %
363 % %
364 % %
365 % I s W i n d o w s 9 5 %
366 % %
367 % %
368 % %
369 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
370 %
371 % Method IsWindows95 returns true if the system is Windows 95.
372 %
373 % The format of the IsWindows95 method is:
374 %
375 % int IsWindows95()
376 %
377 % A description of each parameter follows:
378 %
379 % o status: an integer value representing the status of the terminating
380 % process.
381 %
382 %
383 */
IsWindows95()384 MagickExport MagickBool IsWindows95()
385 {
386 OSVERSIONINFO
387 version_info;
388
389 version_info.dwOSVersionInfoSize=sizeof(version_info);
390 if (GetVersionEx(&version_info) &&
391 (version_info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS))
392 return(MagickTrue);
393 return(MagickFalse);
394 }
395
396 /*
397 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
398 % %
399 % %
400 % %
401 % InitializeWIN32ExceptionHandlers %
402 % %
403 % %
404 % %
405 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
406 %
407 % Method InitializeWIN32ExceptionHandlers registers a handler for WIN32
408 % exceptions (similar to POSIX signals but different).
409 %
410 % The format of the InitializeWIN32ExceptionHandlers method is:
411 %
412 % void InitializeWIN32ExceptionHandlers()
413 %
414 %
415 */
416 static LONG WINAPI
MagickUnhandledExceptionFilter(struct _EXCEPTION_POINTERS * info)417 MagickUnhandledExceptionFilter(struct _EXCEPTION_POINTERS *info)
418 {
419 /*
420 https://msdn.microsoft.com/en-us/library/windows/desktop/ms680634%28v=vs.85%29.aspx
421
422 http://www.codeproject.com/Articles/11132/Walking-the-callstack
423
424 http://www.microsoft.com/msj/0197/exception/exception.aspx
425
426 Return values:
427
428 EXCEPTION_EXECUTE_HANDLER (0x1)
429
430 Return from UnhandledExceptionFilter and execute the associated
431 exception handler. This usually results in process termination.
432
433 EXCEPTION_CONTINUE_EXECUTION (0xffffffff)
434
435 Return from UnhandledExceptionFilter and continue execution from
436 the point of the exception. Note that the filter function is
437 free to modify the continuation state by modifying the exception
438 information supplied through its LPEXCEPTION_POINTERS parameter.
439
440 EXCEPTION_CONTINUE_SEARCH (0x0)
441
442 Proceed with normal execution of UnhandledExceptionFilter. That
443 means obeying the SetErrorMode flags, or invoking the
444 Application Error pop-up message box.
445
446 The EXCEPTION_POINTERS structure has the definition:
447
448 https://msdn.microsoft.com/en-us/library/windows/desktop/aa363082%28v=vs.85%29.aspx
449 typedef struct _EXCEPTION_RECORD {
450 DWORD ExceptionCode;
451 DWORD ExceptionFlags;
452 struct _EXCEPTION_RECORD *ExceptionRecord;
453 PVOID ExceptionAddress;
454 DWORD NumberParameters;
455 ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
456 } EXCEPTION_RECORD, *PEXCEPTION_RECORD;
457
458 https://msdn.microsoft.com/en-us/library/windows/desktop/ms679284%28v=vs.85%29.aspx
459 We don't care about PCONTEXT because it is processor-specific and includes low level
460 details such as register contents.
461
462 https://msdn.microsoft.com/en-us/library/windows/desktop/ms679331%28v=vs.85%29.aspx
463 typedef struct _EXCEPTION_POINTERS {
464 PEXCEPTION_RECORD ExceptionRecord;
465 PCONTEXT ContextRecord;
466 } EXCEPTION_POINTERS, *PEXCEPTION_POINTERS;
467
468 */
469 static const struct {
470 DWORD code;
471 const char *text;
472 }
473 except_descr[] =
474 {
475 /*
476 The thread tried to read from or write to a virtual address
477 for which it does not have the appropriate access.
478 */
479 #if defined(EXCEPTION_ACCESS_VIOLATION)
480 { EXCEPTION_ACCESS_VIOLATION, "Access violation" },
481 #endif
482 /*
483 The thread tried to access an array element that is out of
484 bounds and the underlying hardware supports bounds checking.
485 */
486 #if defined(EXCEPTION_ARRAY_BOUNDS_EXCEEDED)
487 { EXCEPTION_ARRAY_BOUNDS_EXCEEDED, "Array bounds exceeded" },
488 #endif
489 /*
490 The thread tried to read or write data that is misaligned on
491 hardware that does not provide alignment. For example,
492 16-bit values must be aligned on 2-byte boundaries; 32-bit
493 values on 4-byte boundaries, and so on.
494 */
495 #if defined(EXCEPTION_DATATYPE_MISALIGNMENT)
496 { EXCEPTION_DATATYPE_MISALIGNMENT, "Datatype misalignment" },
497 #endif
498 /*
499 One of the operands in a floating-point operation is
500 denormal. A denormal value is one that is too small to
501 represent as a standard floating-point value.
502 */
503 #if defined(EXCEPTION_FLT_DENORMAL_OPERAND)
504 { EXCEPTION_FLT_DENORMAL_OPERAND, "Float - denormal operand" },
505 #endif
506 /*
507 The thread tried to divide a floating-point value by a
508 floating-point divisor of zero.
509 */
510 #if defined(EXCEPTION_FLT_DIVIDE_BY_ZERO)
511 { EXCEPTION_FLT_DIVIDE_BY_ZERO, "Float - divide by zero" },
512 #endif
513 /*
514 This exception represents any floating-point exception not
515 included in this list.
516 */
517 #if defined(EXCEPTION_FLT_INVALID_OPERATION)
518 { EXCEPTION_FLT_INVALID_OPERATION, "Float - invalid operation" },
519 #endif
520 /*
521 The exponent of a floating-point operation is greater than the
522 magnitude allowed by the corresponding type.
523 */
524 #if defined(EXCEPTION_FLT_OVERFLOW)
525 { EXCEPTION_FLT_OVERFLOW, "Float overflow" },
526 #endif
527 /*
528 The stack overflowed or underflowed as the result of a
529 floating-point operation.
530 */
531 #if defined(EXCEPTION_FLT_STACK_CHECK)
532 { EXCEPTION_FLT_STACK_CHECK, "Float - stack under/overflow" },
533 #endif
534 /*
535 The exponent of a floating-point operation is less than the
536 magnitude allowed by the corresponding type.
537 */
538 #if defined(EXCEPTION_FLT_UNDERFLOW)
539 { EXCEPTION_FLT_UNDERFLOW, "Float - underflow" },
540 #endif
541 /*
542 The thread tried to execute an invalid instruction.
543 */
544 #if defined(EXCEPTION_ILLEGAL_INSTRUCTION)
545 { EXCEPTION_ILLEGAL_INSTRUCTION, "Illegal instruction" },
546 #endif
547 /*
548 The thread tried to access a page that was not present, and
549 the system was unable to load the page. For example, this
550 exception might occur if a network connection is lost while
551 running a program over the network.
552 */
553 #if defined(EXCEPTION_IN_PAGE_ERROR)
554 { EXCEPTION_IN_PAGE_ERROR, "MMU page-in error" },
555 #endif
556 /*
557 The thread tried to divide an integer value by an integer
558 divisor of zero.
559 */
560 #if defined(EXCEPTION_INT_DIVIDE_BY_ZERO)
561 { EXCEPTION_INT_DIVIDE_BY_ZERO, "Integer divide by zero" },
562 #endif
563 /*
564 The result of an integer operation caused a carry out of the
565 most significant bit of the result.
566 */
567 #if defined(EXCEPTION_INT_OVERFLOW)
568 { EXCEPTION_INT_OVERFLOW, "Integer overflow" },
569 #endif
570 /*
571 The thread tried to execute an instruction whose operation is
572 not allowed in the current machine mode.
573 */
574 #if defined(EXCEPTION_PRIV_INSTRUCTION)
575 { EXCEPTION_PRIV_INSTRUCTION, "Privileged instruction" },
576 #endif
577 /*
578 The thread used up its stack.
579 */
580 #if defined(EXCEPTION_STACK_OVERFLOW)
581 { EXCEPTION_STACK_OVERFLOW, "Stack overflow" }
582 #endif
583 };
584
585 char
586 message[MaxTextExtent];
587
588 const char
589 *text = NULL;
590
591 size_t
592 i;
593
594 DWORD
595 code = info->ExceptionRecord->ExceptionCode;
596
597 /*
598 Linear search for explanation of error code.
599 */
600 for (i=0; i < sizeof(except_descr)/sizeof(except_descr[0]); i++)
601 if (except_descr[i].code == code)
602 {
603 text = except_descr[i].text;
604 break;
605 }
606
607 /*
608 If this is an exception we handle
609 */
610 if (text != NULL)
611 {
612 /*
613 Release persistent resources
614 */
615 PanicDestroyMagick();
616
617 /*
618 Output messages like:
619
620 gm.exe identify: caught exception 0xC0000005 "Access violation"...
621 */
622 FormatString(message,
623 "%s: caught exception 0x%08X \"%s\"...",
624 GetClientName(), (unsigned int) code, text);
625 if (write(STDERR_FILENO,message,
626 (MAGICK_POSIX_IO_SIZE_T) strlen(message)) == -1)
627 {
628 /* Exists to quench warning */
629 }
630
631 /*
632 Return from UnhandledExceptionFilter and execute the
633 associated exception handler. This usually results in process
634 termination.
635 */
636 return EXCEPTION_EXECUTE_HANDLER;
637 }
638
639 /*
640 Can also look at ExceptionFlags and check for EXCEPTION_NONCONTINUABLE.
641 */
642
643 /*
644 Proceed with normal execution of UnhandledExceptionFilter. That
645 means obeying the SetErrorMode flags, or invoking the Application
646 Error pop-up message box.
647 */
648 return EXCEPTION_CONTINUE_SEARCH;
649 }
650 MagickExport void
NTInitializeExceptionHandlers()651 NTInitializeExceptionHandlers()
652 {
653
654 (void) SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX |
655 SEM_NOOPENFILEERRORBOX);
656 (void) SetUnhandledExceptionFilter(MagickUnhandledExceptionFilter);
657 }
658
659 #if !defined(HasLTDL)
660 /*
661 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
662 % %
663 % %
664 % %
665 % N T d l c l o s e %
666 % %
667 % %
668 % %
669 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
670 %
671 % Method NTdlclose unloads the module associated with the passed handle.
672 % Zero is returned on success.
673 %
674 % The format of the NTdlclose method is:
675 %
676 % void NTdlclose(void *handle)
677 %
678 % A description of each parameter follows:
679 %
680 % o handle: Specifies a handle to a previously loaded dynamic module.
681 %
682 */
NTdlclose(void * handle)683 MagickExport int NTdlclose(void *handle)
684 {
685 /* FreeLibrary returns zero for failure */
686 return (!(FreeLibrary(handle)));
687 }
688
689 /*
690 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
691 % %
692 % %
693 % %
694 % N T d l e r r o r %
695 % %
696 % %
697 % %
698 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
699 %
700 % Method NTdlerror returns a pointer to a string describing the last error
701 % associated with a NTdl* function. Note that this function is not thread
702 % safe so it should only be used under the protection of a lock.
703 %
704 % The format of the NTdlerror method is:
705 %
706 % const char * NTdlerror(void)
707 %
708 % A description of each parameter follows:
709 %
710 */
NTdlerror(void)711 MagickExport const char *NTdlerror(void)
712 {
713 static char
714 last_error[MaxTextExtent];
715
716 char
717 *error;
718
719 last_error[0]='\0';
720 error=NTGetLastError();
721 if (error)
722 strlcpy(last_error,error,MaxTextExtent);
723 MagickFreeMemory(error);
724 return (last_error);
725 }
726
727 /*
728 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
729 % %
730 % %
731 % %
732 % N T d l e x i t %
733 % %
734 % %
735 % %
736 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
737 %
738 % NTdlexit() exits the dynamic module loading subsystem.
739 %
740 % The format of the NTdlexit method is:
741 %
742 % int NTdlexit(void)
743 %
744 */
NTdlexit(void)745 MagickExport int NTdlexit(void)
746 {
747 return(0);
748 }
749
750 /*
751 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
752 % %
753 % %
754 % %
755 % N T d l i n i t %
756 % %
757 % %
758 % %
759 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
760 %
761 % Method NTdlinit initializes the dynamic module loading subsystem.
762 %
763 % The format of the NTdlinit method is:
764 %
765 % int NTdlinit(void)
766 %
767 */
NTdlinit(void)768 MagickExport int NTdlinit(void)
769 {
770 return(0);
771 }
772
773 /*
774 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
775 % %
776 % %
777 % %
778 % N T d l o p e n %
779 % %
780 % %
781 % %
782 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
783 %
784 % Method NTdlopen loads a dynamic module into memory and returns a handle
785 % that can be used to access the various procedures in the module.
786 %
787 % The format of the NTdlopen method is:
788 %
789 % void *NTdlopen(const char *filename)
790 %
791 % A description of each parameter follows:
792 %
793 % o path: Specifies a pointer to string representing dynamic module that
794 % is to be loaded.
795 %
796 */
NTdlopen(const char * filename)797 MagickExport void *NTdlopen(const char *filename)
798 {
799 #define MaxPathElements 31
800
801 char
802 buffer[MaxTextExtent];
803
804 int
805 index;
806
807 register char
808 *p,
809 *q;
810
811 register int
812 i;
813
814 void
815 *handle;
816
817 UINT
818 errorMode;
819
820 // Set error mode so that dialog box is not displayed on error.
821 errorMode=SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
822
823 // Load library via name
824 handle=(void *) LoadLibrary(filename);
825
826 // If library failed to load, but a search path is defined, then
827 // attempt to load library via search path.
828 if ((handle == (void *) NULL) && (NTslsearchpath != NULL))
829 {
830 p=NTslsearchpath;
831 index=0;
832 while (index < MaxPathElements)
833 {
834 q=strchr(p,DirectoryListSeparator);
835 if (q == (char *) NULL)
836 {
837 (void) strlcpy(buffer,p,MaxTextExtent);
838 (void) strlcat(buffer,"\\",MaxTextExtent);
839 (void) strlcat(buffer,filename,MaxTextExtent);
840 handle=(void *) LoadLibrary(buffer);
841 break;
842 }
843 i=q-p;
844 (void) strncpy(buffer,p,i);
845 buffer[i]='\0';
846 (void) strlcat(buffer,"\\",MaxTextExtent);
847 (void) strlcat(buffer,filename,MaxTextExtent);
848 handle=(void *) LoadLibrary(buffer);
849 if (handle)
850 break;
851 p=q+1;
852 }
853 }
854
855 // Restore original error handling mode.
856 SetErrorMode(errorMode);
857
858 return(handle);
859 }
860
861 /*
862 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
863 % %
864 % %
865 % %
866 % N T d l s e t s e a r c h p a t h %
867 % %
868 % %
869 % %
870 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
871 %
872 % Method NTdlsetsearchpath sets the current locations that the subsystem
873 % should look at to find dynamically loadable modules.
874 %
875 % The format of the NTdlsetsearchpath method is:
876 %
877 % int NTdlsetsearchpath(char *path)
878 %
879 % A description of each parameter follows:
880 %
881 % o path: Specifies a pointer to string representing the search path
882 % for DLL's that can be dynamically loaded.
883 %
884 */
NTdlsetsearchpath(const char * path)885 MagickExport int NTdlsetsearchpath(const char *path)
886 {
887 if (NTslsearchpath)
888 {
889 MagickFreeMemory(NTslsearchpath);
890 NTslsearchpath=(char *) NULL;
891 }
892 if (path != (char *) NULL)
893 NTslsearchpath=AllocateString(path);
894 return (0);
895 }
896
897 /*
898 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
899 % %
900 % %
901 % %
902 % N T d l s y m %
903 % %
904 % %
905 % %
906 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
907 %
908 % Method NTdlsym retrieve the procedure address of the procedure specified
909 % by the passed character string.
910 %
911 % The format of the NTdlsym method is:
912 %
913 % void *NTdlsym(void *handle,const char *name)
914 %
915 % A description of each parameter follows:
916 %
917 % o handle: Specifies a handle to the previously loaded dynamic module.
918 %
919 % o name: Specifies the procedure entry point to be returned.
920 %
921 */
NTdlsym(void * handle,const char * name)922 MagickExport void *NTdlsym(void *handle,const char *name)
923 {
924 LPFNDLLFUNC1
925 lpfnDllFunc1;
926
927 /* FARPROC GetProcAddress(HMODULE hModule,LPCSTR lpProcName); */
928 lpfnDllFunc1=(LPFNDLLFUNC1) GetProcAddress(handle,name);
929 if (!lpfnDllFunc1)
930 return((void *) NULL);
931 return((void *) lpfnDllFunc1);
932 }
933 #endif /* !defined(HasLTDL) */
934
935 /*
936 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
937 % %
938 % %
939 % %
940 + N T m u n m a p %
941 % %
942 % %
943 % %
944 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
945 %
946 % Method NTmunmap emulates the POSIX munmap function.
947 %
948 % The format of the NTmunmap method is:
949 %
950 % int NTmunmap(void *map,size_t length)
951 %
952 % A description of each parameter follows:
953 %
954 % o status: Method NTmunmap returns 0 on success; otherwise, it
955 % returns -1 and sets errno to indicate the error.
956 %
957 % o map: The address of the binary large object.
958 %
959 % o length: The length of the binary large object.
960 %
961 %
962 */
NTmunmap(void * map,size_t length)963 MagickExport int NTmunmap(void *map,size_t length)
964 {
965 ARG_NOT_USED(length);
966
967 if (!UnmapViewOfFile(map))
968 return(-1);
969 return(0);
970 }
971
972 /*
973 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
974 % %
975 % %
976 % %
977 % N T E l a p s e d T i m e %
978 % %
979 % %
980 % %
981 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
982 %
983 % Method NTElapsedTime returns the elapsed time (in seconds) since the last
984 % call to StartTimer().
985 %
986 % The format of the ElapsedTime method is:
987 %
988 % double NTElapsedTime(void)
989 %
990 %
991 */
NTElapsedTime(void)992 MagickExport double NTElapsedTime(void)
993 {
994 /*
995 See
996 https://msdn.microsoft.com/en-us/library/windows/desktop/ms644905%28v=vs.85%29.aspx
997 https://msdn.microsoft.com/en-us/library/windows/desktop/ms644904%28v=vs.85%29.aspx
998 */
999 static LARGE_INTEGER pFrequency = {0};
1000 LARGE_INTEGER CurrentTime;
1001
1002 if (pFrequency.QuadPart == 0)
1003 if (QueryPerformanceFrequency(&pFrequency) == 0)
1004 pFrequency.QuadPart = 1; /* Mark that the Performance counter is NOT supported. */
1005
1006 if (pFrequency.QuadPart > 1)
1007 {
1008 QueryPerformanceCounter(&CurrentTime);
1009 return (double) CurrentTime.QuadPart / pFrequency.QuadPart;
1010 }
1011 else
1012 {
1013 union
1014 {
1015 FILETIME
1016 filetime;
1017
1018 __int64
1019 filetime64;
1020 } elapsed_time;
1021
1022 SYSTEMTIME
1023 system_time;
1024
1025 GetSystemTime(&system_time);
1026 SystemTimeToFileTime(&system_time,&elapsed_time.filetime);
1027 return((double) 1.0e-7*elapsed_time.filetime64);
1028 }
1029 }
1030
1031 /*
1032 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1033 % %
1034 % %
1035 % %
1036 + N T E r r o r H a n d l e r %
1037 % %
1038 % %
1039 % %
1040 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1041 %
1042 % Method NTErrorHandler displays an error reason and then terminates
1043 % the program.
1044 %
1045 % The format of the NTErrorHandler method is:
1046 %
1047 % void NTErrorHandler(const ExceptionType error,const char *reason,
1048 % const char *description)
1049 %
1050 % A description of each parameter follows:
1051 %
1052 % o error: Specifies the numeric error category.
1053 %
1054 % o reason: Specifies the reason to display before terminating the
1055 % program.
1056 %
1057 % o description: Specifies any description to the reason.
1058 %
1059 %
1060 */
NTErrorHandler(const ExceptionType error,const char * reason,const char * description)1061 MagickExport void NTErrorHandler(const ExceptionType error,const char *reason,
1062 const char *description)
1063 {
1064 char
1065 buffer[3*MaxTextExtent];
1066
1067 ARG_NOT_USED(error);
1068
1069 if (reason == (char *) NULL)
1070 {
1071 DestroyMagick();
1072 Exit(0);
1073 }
1074 if ((description != (char *) NULL) && errno)
1075 FormatString(buffer,"%.1024s: %.1024s (%.1024s) [%.1024s].\n",
1076 GetClientName(),reason,description,strerror(errno));
1077 else
1078 if (description != (char *) NULL)
1079 FormatString(buffer,"%.1024s: %.1024s (%.1024s).\n",
1080 GetClientName(),reason,description);
1081 else
1082 if (errno)
1083 FormatString(buffer,"%.1024s: %.1024s [%.1024s].\n",
1084 GetClientName(),reason,strerror(errno));
1085 else
1086 FormatString(buffer,"%.1024s: %.1024s.\n",GetClientName(),
1087 reason);
1088 (void) MessageBox(NULL,buffer,"GraphicsMagick Exception",MB_OK | MB_TASKMODAL |
1089 MB_SETFOREGROUND | MB_ICONEXCLAMATION);
1090 DestroyMagick();
1091 Exit(0);
1092 }
1093
1094 /*
1095 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1096 % %
1097 % %
1098 % %
1099 % N T G e t E x e c u t i o n P a t h %
1100 % %
1101 % %
1102 % %
1103 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1104 %
1105 % Method NTGetExecutionPath returns the execution path of a program.
1106 %
1107 % The format of the GetExecutionPath method is:
1108 %
1109 % unsigned int NTGetExecutionPath(char *path)
1110 %
1111 %
1112 */
NTGetExecutionPath(char * path)1113 MagickExport MagickPassFail NTGetExecutionPath(char *path)
1114 {
1115 GetModuleFileName(0,path,MaxTextExtent);
1116 return(MagickPass);
1117 }
1118
1119 /*
1120 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1121 % %
1122 % %
1123 % %
1124 % N T G e t L a s t E r r o r %
1125 % %
1126 % %
1127 % %
1128 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1129 %
1130 % Method NTGetLastError returns the last error that occurred.
1131 %
1132 % The format of the NTGetLastError method is:
1133 %
1134 % char *NTGetLastError(void)
1135 %
1136 % A description of each parameter follows:
1137 %
1138 */
NTGetLastError(void)1139 char *NTGetLastError(void)
1140 {
1141 char
1142 *reason;
1143
1144 int
1145 status;
1146
1147 LPVOID
1148 buffer;
1149
1150 status=FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
1151 FORMAT_MESSAGE_FROM_SYSTEM,NULL,GetLastError(),
1152 MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),(LPTSTR) &buffer,0,NULL);
1153 if (!status)
1154 reason=AllocateString("An unknown error occurred");
1155 else
1156 {
1157 reason=AllocateString((const char *)buffer);
1158 LocalFree(buffer);
1159 }
1160 return(reason);
1161 }
1162
1163 /*
1164 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1165 % %
1166 % %
1167 % %
1168 % N T G h o s t s c r i p t D L L %
1169 % %
1170 % %
1171 % %
1172 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1173 %
1174 % Method NTGhostscriptDLL obtains the path to the latest Ghostscript DLL.
1175 % The method returns False if a value is not obtained.
1176 %
1177 % The format of the NTGhostscriptDLL method is:
1178 %
1179 % int NTGhostscriptDLL(char *path, int path_length)
1180 %
1181 % A description of each parameter follows:
1182 %
1183 % o path: Pointer to buffer in which to return result.
1184 %
1185 % o path_length: Length of buffer
1186 %
1187 */
1188 /*
1189 Get a named registry value.
1190 Key = hkeyroot\\key, named value = name.
1191 */
1192 static int
NTGetRegistryValue(HKEY hkeyroot,const char * key,const char * name,char * ptr,int * plen)1193 NTGetRegistryValue(HKEY hkeyroot, const char *key, const char *name,
1194 char *ptr, int *plen)
1195 {
1196 HKEY
1197 hkey;
1198
1199 DWORD
1200 cbData,
1201 keytype;
1202
1203 BYTE
1204 b,
1205 *bptr = (BYTE *)ptr;
1206
1207 LONG
1208 rc;
1209
1210 if (RegOpenKeyExA(hkeyroot, key, 0, KEY_READ, &hkey)
1211 == ERROR_SUCCESS)
1212 {
1213 keytype = REG_SZ;
1214 cbData = *plen;
1215 if (bptr == (BYTE *) NULL)
1216 bptr = &b; /* Registry API won't return ERROR_MORE_DATA */
1217 /* if ptr is NULL */
1218 rc = RegQueryValueExA(hkey, (char *)name, 0, &keytype, bptr, &cbData);
1219 RegCloseKey(hkey);
1220 if (rc == ERROR_SUCCESS)
1221 {
1222 *plen = cbData;
1223 return 0; /* found environment variable and copied it */
1224 }
1225 else
1226 if (rc == ERROR_MORE_DATA)
1227 {
1228 /* buffer wasn't large enough */
1229 *plen = cbData;
1230 return -1;
1231 }
1232 }
1233 return 1; /* not found */
1234 }
1235
1236 /*
1237 Find the latest version of Ghostscript installed on the system (if
1238 any).
1239 */
1240 static MagickPassFail
NTGhostscriptFind(const char ** gs_productfamily,int * gs_major_version,int * gs_minor_version)1241 NTGhostscriptFind(const char **gs_productfamily,
1242 int *gs_major_version,
1243 int *gs_minor_version)
1244 {
1245 /*
1246 These are the Ghostscript product versions we will search for.
1247 */
1248 const char *products[4] =
1249 {
1250 "GPL Ghostscript",
1251 "GNU Ghostscript",
1252 "AFPL Ghostscript",
1253 "Aladdin Ghostscript"
1254 };
1255
1256 unsigned int
1257 product_index,
1258 whence;
1259
1260 MagickPassFail
1261 status;
1262
1263 status=MagickFail;
1264 *gs_productfamily=NULL;
1265
1266 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1267 "Searching for Ghostscript...");
1268
1269 /* Minimum version of Ghostscript is 5.50 */
1270 *gs_major_version=5;
1271 *gs_minor_version=49;
1272 for(whence=0; whence<=1; whence++)
1273 {
1274 const HKEY hkeyroot = hkeys[whence].hkey;
1275 const char *KeyRootStr = hkeys[whence].name;
1276
1277 for(product_index=0; product_index < sizeof(products)/sizeof(products[0]); ++product_index)
1278 {
1279 HKEY hkey;
1280 LONG winstatus;
1281
1282 REGSAM
1283 open_key_mode;
1284
1285 char
1286 key[MaxTextExtent],
1287 last_error_msg[MaxTextExtent];
1288
1289 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1290 " Searching for %s...",
1291 products[product_index]);
1292 FormatString(key,"SOFTWARE\\%s",products[product_index]);
1293
1294 /*
1295 long WINAPI RegOpenKeyEx(const HKEY hKey, const LPCTSTR
1296 lpSubKey, const DWORD ulOptions, const REGSAM samDesired,
1297 PHKEY phkResult)
1298 */
1299 open_key_mode=KEY_READ;
1300 if ((winstatus=RegOpenKeyExA(hkeyroot, key, 0, open_key_mode, &hkey))
1301 == ERROR_SUCCESS)
1302 {
1303 DWORD
1304 cbData;
1305
1306 int
1307 n;
1308
1309 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1310 " RegOpenKeyExA() opened "
1311 "\"%s\\%s\"",
1312 KeyRootStr, key);
1313 /* Now enumerate the keys */
1314 cbData = sizeof(key) / sizeof(char);
1315 n=0;
1316 /*
1317 LONG WINAPI RegEnumKeyEx(HKEY hKey, DWORD dwIndex, LPTSTR
1318 lpName, LPDWORD lpcName, LPDWORD lpReserved, LPTSTR
1319 lpClass, LPDWORD lpcClass, PFILETIME lpftLastWriteTime)
1320
1321 Enumerates the subkeys of the specified open registry key.
1322
1323 RegEnumKeyA is is provided only for compatibility with
1324 16-bit versions of Windows.
1325 */
1326 while ((winstatus=RegEnumKeyA(hkey, n, key, cbData)) == ERROR_SUCCESS)
1327 {
1328 int
1329 major_version,
1330 minor_version;
1331
1332 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1333 " RegEnumKeyA enumerated \"%s\"",key);
1334 n++;
1335 major_version=0;
1336 minor_version=0;
1337 if (sscanf(key,"%d.%d",&major_version,&minor_version) != 2)
1338 continue;
1339
1340 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1341 " Found Ghostscript (%s) version %d.%02d",
1342 products[product_index],
1343 major_version,
1344 minor_version);
1345
1346 if ((major_version > *gs_major_version) ||
1347 ((major_version == *gs_major_version) &&
1348 (minor_version > *gs_minor_version)))
1349 {
1350 *gs_productfamily=products[product_index];
1351 *gs_major_version=major_version;
1352 *gs_minor_version=minor_version;
1353 status=MagickPass;
1354 }
1355 }
1356 if (winstatus != ERROR_NO_MORE_ITEMS)
1357 {
1358 (void) NTstrerror_r(winstatus,last_error_msg,sizeof(last_error_msg));
1359 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1360 " RegEnumKeyA (%s)",
1361 last_error_msg);
1362 }
1363 /*
1364 LONG WINAPI RegCloseKey(HKEY hKey)
1365
1366 Close the registry key.
1367 */
1368 winstatus=RegCloseKey(hkey);
1369 }
1370 else
1371 {
1372 /*
1373 If the function fails, the return value is a nonzero error
1374 code defined in Winerror.h. You can use the FormatMessage
1375 function with the FORMAT_MESSAGE_FROM_SYSTEM flag to get a
1376 generic description of the error.
1377 */
1378 (void) NTstrerror_r(winstatus,last_error_msg,sizeof(last_error_msg));
1379 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1380 " RegOpenKeyExA() failed to open "
1381 "\"%s\\%s\" (%s)", KeyRootStr,
1382 key,last_error_msg);
1383 }
1384 }
1385 }
1386
1387 if (status != MagickFail)
1388 {
1389 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1390 "Selected Ghostscript (%s) version %d.%02d",
1391 *gs_productfamily,*gs_major_version,
1392 *gs_minor_version);
1393 }
1394 else
1395 {
1396 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1397 "Failed to find Ghostscript!");
1398 *gs_major_version=0;
1399 *gs_minor_version=0;
1400 }
1401
1402 return status;
1403 }
1404
1405
1406 /*
1407 Obtain a string from the installed Ghostscript (if any).
1408 */
1409 static MagickPassFail
NTGhostscriptGetString(const char * name,char * ptr,const size_t len)1410 NTGhostscriptGetString(const char *name, char *ptr, const size_t len)
1411 {
1412 static const char
1413 *gs_productfamily=NULL;
1414
1415 static int
1416 gs_major_version=0,
1417 gs_minor_version=0;
1418
1419 unsigned int
1420 i;
1421
1422 int
1423 length;
1424
1425 char
1426 key[MaxTextExtent];
1427
1428 ptr[0]='\0';
1429
1430 if (NULL == gs_productfamily)
1431 (void) NTGhostscriptFind(&gs_productfamily,&gs_major_version,
1432 &gs_minor_version);
1433
1434 if (NULL == gs_productfamily)
1435 return MagickFail;
1436
1437 FormatString(key,"SOFTWARE\\%s\\%d.%02d",gs_productfamily,
1438 gs_major_version, gs_minor_version);
1439
1440 for (i=0; i < sizeof(hkeys)/sizeof(hkeys[0]); ++i)
1441 {
1442 length = (int) len;
1443 if (NTGetRegistryValue(hkeys[i].hkey, key, name, ptr, &length) == 0)
1444 {
1445 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1446 "Registry: \"%s\\%s\\%s\"=\"%s\"",
1447 hkeys[i].name,key,name,ptr);
1448 return MagickPass;
1449 }
1450 else
1451 {
1452 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1453 "Failed lookup: \"%s\\%s\\%s\"",
1454 hkeys[i].name,key,name);
1455 }
1456 }
1457
1458 return MagickFail;
1459 }
1460 #if defined(HasGS)
1461
1462 /*
1463 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1464 % %
1465 % %
1466 % %
1467 % N T G h o s t s c r i p t D L L %
1468 % %
1469 % %
1470 % %
1471 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1472 %
1473 % Method NTGhostscriptDLL obtains the path to the latest Ghostscript DLL.
1474 % The method returns False if a value is not obtained.
1475 %
1476 % The format of the NTGhostscriptDLL method is:
1477 %
1478 % int NTGhostscriptDLL( char *path, int path_length)
1479 %
1480 % A description of each parameter follows:
1481 %
1482 % o path: Pointer to path buffer to update
1483 %
1484 % o path_length: Allocation size of path buffer.
1485 %%
1486 */
NTGhostscriptDLL(char * path,int path_length)1487 MagickExport int NTGhostscriptDLL(char *path, int path_length)
1488 {
1489 static char
1490 cache[MaxTextExtent],
1491 *result=NULL;
1492
1493 path[0]='\0';
1494
1495 if (NULL == result)
1496 {
1497 const char
1498 *directory;
1499
1500 directory=getenv("MAGICK_GHOSTSCRIPT_PATH");
1501 if (directory != (const char *) NULL)
1502 {
1503 FormatString(cache, "%.1024s%sgsdll%u.dll", directory,
1504 DirectorySeparator, (unsigned int) sizeof(directory)*8);
1505 if (IsAccessibleAndNotEmpty(cache))
1506 result=cache;
1507 else
1508 (void) LogMagickEvent(ConfigureEvent, GetMagickModule(),
1509 "Unable to find ghostscript library: \"%s\"", cache);
1510 }
1511 else if (NTGhostscriptGetString("GS_DLL", cache, sizeof(cache)))
1512 {
1513 result=cache;
1514 }
1515 }
1516
1517 if (result)
1518 {
1519 (void) strlcpy(path, result, path_length);
1520 return TRUE;
1521 }
1522
1523 return FALSE;
1524 }
1525
1526 /*
1527 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1528 % %
1529 % %
1530 % %
1531 % N T G h o s t s c r i p t D L L V e c t o r s %
1532 % %
1533 % %
1534 % %
1535 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1536 %
1537 % Method NTGhostscriptDLLVectors returns a GhostscriptVectors structure
1538 % containing function vectors to invoke Ghostscript DLL functions. A null
1539 % pointer is returned if there is an error with loading the DLL or
1540 % retrieving the function vectors.
1541 %
1542 % The format of the NTGhostscriptDLLVectors method is:
1543 %
1544 % const GhostscriptVectors *NTGhostscriptDLLVectors( void )
1545 %
1546 %%
1547 */
NTGhostscriptDLLVectors(void)1548 MagickExport const GhostscriptVectors *NTGhostscriptDLLVectors( void )
1549 {
1550 if (NTGhostscriptLoadDLL())
1551 return &gs_vectors;
1552
1553 return (GhostscriptVectors*) NULL;
1554 }
1555
1556 /*
1557 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1558 % %
1559 % %
1560 % %
1561 % N T G h o s t s c r i p t E X E %
1562 % %
1563 % %
1564 % %
1565 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1566 %
1567 % Method NTGhostscriptEXE obtains the path to the latest Ghostscript
1568 % executable. The method returns TRUE if path is updated, otherwise
1569 % FALSE. When the full path value is not obtained, then the value
1570 % "gswin32c.exe" or "gswin64c.exe" is used.
1571 %
1572 % The format of the NTGhostscriptEXE method is:
1573 %
1574 % int NTGhostscriptEXE(char *path, int path_length)
1575 %
1576 % A description of each parameter follows:
1577 %
1578 % o path: Pointer to buffer in which to return result.
1579 %
1580 % o path_length: Length of buffer
1581 %
1582 */
NTGhostscriptEXE(char * path,int path_length)1583 MagickExport int NTGhostscriptEXE(char *path, int path_length)
1584 {
1585 static char
1586 cache[MaxTextExtent],
1587 *result=NULL;
1588
1589 if (NULL == result)
1590 {
1591 char
1592 gsexe[MaxTextExtent];
1593
1594 char
1595 *p;
1596
1597 /* Ensure a suitable default. */
1598 (void) FormatString(gsexe,"gswin%uc.exe",(unsigned int) sizeof(p)*8);
1599 (void) strlcpy(cache,gsexe,sizeof(cache));
1600
1601 if (NTGhostscriptDLL(cache,sizeof(cache)))
1602 {
1603 p = strrchr(cache, '\\');
1604 if (p) {
1605 p++;
1606 *p = 0;
1607 (void) strlcat(cache,gsexe,sizeof(cache));
1608 }
1609 }
1610 result=cache;
1611 }
1612
1613 if (result)
1614 {
1615 (void) strlcpy(path,result, path_length);
1616 return TRUE;
1617 }
1618
1619 return FALSE;
1620 }
1621 #endif /* if defined(HasGS) */
1622
1623 /*
1624 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1625 % %
1626 % %
1627 % %
1628 % N T G h o s t s c r i p t F o n t s %
1629 % %
1630 % %
1631 % %
1632 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1633 %
1634 % Method NTGhostscriptFonts obtains the path to the Ghostscript fonts.
1635 % The method returns False if a value is not obtained.
1636 %
1637 % The format of the NTGhostscriptFonts method is:
1638 %
1639 % int NTGhostscriptFonts(char *path, int path_length)
1640 %
1641 % A description of each parameter follows:
1642 %
1643 % o path: Pointer to buffer in which to return result.
1644 %
1645 % o path_length: Length of buffer
1646 %
1647 */
NTGhostscriptFonts(char * path,int path_length)1648 MagickExport int NTGhostscriptFonts(char *path, int path_length)
1649 {
1650 char
1651 gs_lib_path[MaxTextExtent];
1652
1653 path[0]='\0';
1654
1655 if (!NTGhostscriptGetString("GS_LIB", gs_lib_path,sizeof(gs_lib_path)))
1656 return FALSE;
1657
1658 /*
1659 The format of the GS_LIB string is a path similar to
1660
1661 "C:\Program Files\gs\gs9.10\bin;C:\Program Files\gs\gs9.10\lib;C:\Program Files\gs\gs9.10\fonts"
1662
1663 Ghostscript 7.0X does not include the Resource entry.
1664
1665 Search path used by GPL Ghostscript 9.10 (2013-08-30):
1666 C:\Program Files\gs\gs9.10\bin ; C:\Program Files\gs\gs9.10\lib ;
1667 C:\Program Files\gs\gs9.10\fonts ; %rom%Resource/Init/ ; %rom%lib/ ;
1668 c:/gs/gs9.10/Resource/Init ; c:/gs/gs9.10/lib ;
1669 c:/gs/gs9.10/Resource/Font ; c:/gs/fonts
1670
1671 */
1672 {
1673 #define URW_FONT_HELVETICA_FILE "n019003l.pfb"
1674 const char
1675 *end = NULL,
1676 *start = gs_lib_path;
1677
1678 end = start+strlen(start);
1679 while ( start < end )
1680 {
1681 char
1682 font_dir_file[MaxTextExtent];
1683
1684 const char
1685 *separator;
1686
1687 int
1688 length;
1689
1690 separator = strchr(start,DirectoryListSeparator);
1691 if (separator)
1692 length=separator-start;
1693 else
1694 length=end-start;
1695 length = Min(length+1,MaxTextExtent);
1696
1697 (void) strlcpy(font_dir_file,start,length);
1698 (void) strlcat(font_dir_file,DirectorySeparator,MaxTextExtent);
1699 (void) strlcat(font_dir_file,URW_FONT_HELVETICA_FILE,MaxTextExtent);
1700 if (IsAccessible(font_dir_file))
1701 {
1702 (void) strlcpy(path, start, Min(length,path_length));
1703 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1704 "Ghostscript fonts in directory \"%s\"",
1705 path);
1706 return TRUE;
1707 }
1708 start += length;
1709 }
1710
1711
1712 // Second scan will try to get common fonts for all gs versions.
1713 start = gs_lib_path;
1714 end = start + strlen(start);
1715 while ( start < end )
1716 {
1717 char
1718 font_dir_file[MaxTextExtent];
1719
1720 const char
1721 *separator, *gsdir;
1722
1723 int
1724 length;
1725
1726 separator = strchr(start,DirectoryListSeparator);
1727 gsdir = strstr(start,"/gs/gs");
1728 if (gsdir==NULL) gsdir = strstr(start,"\\gs\\gs");
1729 if (gsdir!=NULL && (separator==NULL || gsdir<separator))
1730 {
1731 length = Min((gsdir-start)+5,MaxTextExtent);
1732 (void) strlcpy(font_dir_file,start,length);
1733 (void) strlcat(font_dir_file,"fonts",MaxTextExtent);
1734 (void) strlcat(font_dir_file,DirectorySeparator,MaxTextExtent);
1735 (void) strlcat(font_dir_file,URW_FONT_HELVETICA_FILE,MaxTextExtent);
1736 if (IsAccessible(font_dir_file))
1737 {
1738 (void) strlcpy(path,font_dir_file,Min(length+5,path_length)); // str size "fonts" is 5.
1739 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1740 "Ghostscript common fonts in directory \"%s\"",
1741 path);
1742 return TRUE;
1743 }
1744 }
1745
1746 if (separator==NULL) break;
1747 start = separator + 1;
1748 }
1749 }
1750
1751 {
1752 /*
1753 Check "c:/gs/fonts" since Ghostscript also looks there. This
1754 may be a more convenient place to put fonts since it would be
1755 used by every Ghostscript installation on the system.
1756
1757 This part of the path to check is hard-coded in the Ghostscript
1758 binary via AROOTDIR=c:/gs in base/msvclib.mak and it is highly
1759 unlikely that Windows users will use a Ghostscript built with a
1760 different GS_LIB_DEFAULT (which includes AROOTDIR) definition.
1761 */
1762
1763 const char
1764 gs_font_dir[] = "c:\\gs\\fonts";
1765
1766 char
1767 font_dir_file[MaxTextExtent];
1768
1769 (void) strlcpy(font_dir_file,gs_font_dir,MaxTextExtent);
1770 (void) strlcat(font_dir_file,DirectorySeparator,MaxTextExtent);
1771 (void) strlcat(font_dir_file,URW_FONT_HELVETICA_FILE,MaxTextExtent);
1772 if (IsAccessible(font_dir_file))
1773 {
1774 (void) strlcpy(path,gs_font_dir,path_length);
1775 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1776 "Ghostscript fonts in directory \"%s\"",
1777 path);
1778 return TRUE;
1779 }
1780 }
1781
1782 return FALSE;
1783 }
1784 #if defined(HasGS)
1785
1786 /*
1787 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1788 % %
1789 % %
1790 % %
1791 % N T G h o s t s c r i p t L o a d D L L %
1792 % %
1793 % %
1794 % %
1795 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1796 %
1797 % Method NTGhostscriptLoadDLL attempts to load the Ghostscript DLL
1798 % and returns True if it succeeds.
1799 %
1800 % The format of the NTGhostscriptLoadDLL method is:
1801 %
1802 % int NTGhostscriptLoadDLL(void)
1803 %
1804 %%
1805 */
NTGhostscriptLoadDLL(void)1806 MagickExport int NTGhostscriptLoadDLL(void)
1807 {
1808 char
1809 dll_path[MaxTextExtent];
1810
1811 if (gs_dll_handle != (void *) NULL)
1812 return True;
1813
1814 if (!NTGhostscriptDLL(dll_path,sizeof(dll_path)))
1815 return False;
1816
1817 gs_dll_handle = lt_dlopen(dll_path);
1818 if (gs_dll_handle == (void *) NULL)
1819 return False;
1820
1821 memset((void*)&gs_vectors, 0, sizeof(GhostscriptVectors));
1822
1823 gs_vectors.exit=(int (MagickDLLCall *)(gs_main_instance*))
1824 lt_dlsym(gs_dll_handle,"gsapi_exit");
1825 gs_vectors.init_with_args=(int (MagickDLLCall *)(gs_main_instance *, int, char **))
1826 (lt_dlsym(gs_dll_handle,"gsapi_init_with_args"));
1827 gs_vectors.new_instance=(int (MagickDLLCall *)(gs_main_instance **, void *))
1828 (lt_dlsym(gs_dll_handle,"gsapi_new_instance"));
1829 gs_vectors.run_string=(int (MagickDLLCall *)(gs_main_instance *, const char *, int, int *))
1830 (lt_dlsym(gs_dll_handle,"gsapi_run_string"));
1831 gs_vectors.delete_instance=(void (MagickDLLCall *)(gs_main_instance *))
1832 (lt_dlsym(gs_dll_handle,"gsapi_delete_instance"));
1833
1834 if ((gs_vectors.exit==NULL) ||
1835 (gs_vectors.init_with_args==NULL) ||
1836 (gs_vectors.new_instance==NULL) ||
1837 (gs_vectors.run_string==NULL) ||
1838 (gs_vectors.delete_instance==NULL))
1839 return False;
1840
1841 return True;
1842 }
1843
1844 /*
1845 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1846 % %
1847 % %
1848 % %
1849 % N T G h o s t s c r i p t U n L o a d D L L %
1850 % %
1851 % %
1852 % %
1853 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1854 %
1855 % Method NTGhostscriptUnLoadDLL unloads the Ghostscript DLL if it is loaded.
1856 %
1857 % The format of the NTGhostscriptUnLoadDLL method is:
1858 %
1859 % int NTGhostscriptUnLoadDLL(void)
1860 %
1861 %%
1862 */
NTGhostscriptUnLoadDLL(void)1863 MagickExport int NTGhostscriptUnLoadDLL(void)
1864 {
1865 if (gs_dll_handle != (void *) NULL)
1866 {
1867 lt_dlclose(gs_dll_handle);
1868 gs_dll_handle=(void *) NULL;
1869 memset((void*)&gs_vectors, 0, sizeof(GhostscriptVectors));
1870 return True;
1871 }
1872
1873 return False;
1874 }
1875 #endif /* if defined(HasGS) */
1876
1877 /*
1878 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1879 % %
1880 % %
1881 % %
1882 % N T K e r n e l A P I S u p p o r t e d %
1883 % %
1884 % %
1885 % %
1886 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1887 %
1888 % Method NTKernelAPISupported tests to see if an API symbol is defined in
1889 % kernel32.dll. If it is defined, then presumably the interface can safely
1890 % be used without crashing.
1891 %
1892 % The format of the NTKernelAPISupported method is:
1893 %
1894 % MagickBool NTKernelAPISupported(const char *name)
1895 %
1896 % A description of each parameter follows:
1897 %
1898 % o return: MagickTrue if the symbol is defined, otherwise MagickFalse.
1899 %
1900 % o name: Symbol name.
1901 %
1902 */
NTKernelAPISupported(const char * name)1903 MagickExport MagickBool NTKernelAPISupported(const char *name)
1904 {
1905 return (GetProcAddress(GetModuleHandle("kernel32.dll"),name) == NULL ?
1906 MagickFalse : MagickTrue);
1907 }
1908
1909 /*
1910 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1911 % %
1912 % %
1913 % %
1914 % N T R e g i s t r y K e y L o o k u p %
1915 % %
1916 % %
1917 % %
1918 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1919 %
1920 % Method NTRegistryKeyLookup returns package installation path settings
1921 % stored in the Windows Registry. Path settings are specific to the
1922 % installed package version so that multiple package installations may
1923 % coexist.
1924 %
1925 % Values are stored in the registry under a base path path similar to
1926 % "HKEY_LOCAL_MACHINE/SOFTWARE\GraphicsMagick\1.0\Q:8". The provided subkey
1927 % is appended to this base path to form the full key.
1928 %
1929 % The format of the NTRegistryKeyLookup method is:
1930 %
1931 % char *NTRegistryKeyLookup(const char *subkey)
1932 %
1933 % A description of each parameter follows:
1934 %
1935 % o return: Returns an allocated string containing the value of the key.
1936 % This allocation should be freed by the user once it is no longer
1937 % needed.
1938 %
1939 % o key: Specifies a string that identifies the registry object.
1940 % Currently supported sub-keys include: "BinPath", "ConfigurePath",
1941 % "LibPath", "CoderModulesPath", "FilterModulesPath", "SharePath".
1942 %
1943 */
NTRegistryKeyLookup(const char * subkey)1944 MagickExport unsigned char *NTRegistryKeyLookup(const char *subkey)
1945 {
1946 static HKEY
1947 reg_key = (HKEY) INVALID_HANDLE_VALUE;
1948
1949 /*
1950 Look-up base-key for first access only
1951 */
1952 if (reg_key == (HKEY) INVALID_HANDLE_VALUE)
1953 {
1954 char
1955 package_key[MaxTextExtent];
1956
1957 LONG
1958 res;
1959
1960 FormatString(package_key,"SOFTWARE\\%s\\%s\\Q:%d", MagickPackageName,
1961 MagickLibVersionText,QuantumDepth);
1962
1963 res = RegOpenKeyExA (HKEY_LOCAL_MACHINE, package_key, 0, KEY_READ,
1964 ®_key);
1965
1966 if (res != ERROR_SUCCESS)
1967 {
1968 reg_key = (HKEY) INVALID_HANDLE_VALUE;
1969 return 0;
1970 }
1971 }
1972
1973 /*
1974 Look-up sub-key
1975 */
1976 {
1977 unsigned char
1978 *dest;
1979
1980 DWORD
1981 size,
1982 type;
1983
1984 LONG
1985 res;
1986
1987 size = 32;
1988 dest = MagickAllocateMemory(unsigned char *,size);
1989
1990 if (dest != (unsigned char *) NULL)
1991 {
1992 res = RegQueryValueExA (reg_key, subkey, 0, &type, dest, &size);
1993 if (res == ERROR_MORE_DATA && type == REG_SZ)
1994 {
1995 MagickReallocMemory(unsigned char *,dest,size);
1996 res = RegQueryValueExA (reg_key, subkey, 0, &type, dest, &size);
1997 }
1998
1999 if (type != REG_SZ || res != ERROR_SUCCESS)
2000 {
2001 MagickFreeMemory(dest);
2002 }
2003 }
2004
2005 return dest;
2006 }
2007 }
2008
2009 /*
2010 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2011 % %
2012 % %
2013 % %
2014 % N T R e s o u r c e T o B l o b %
2015 % %
2016 % %
2017 % %
2018 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2019 %
2020 % Method NTResourceToBlob returns a blob containing the contents of the
2021 % resource in the current executable specified by the id parameter. This
2022 % is currently used to retrieve MGK files tha have been embedded into
2023 % the various command line utilities.
2024 %
2025 % The format of the telldir method is:
2026 %
2027 % unsigned char *NTResourceToBlob(const char *id)
2028 %
2029 % A description of each parameter follows:
2030 %
2031 % o id: Specifies a string that identifies the resource.
2032 %
2033 %
2034 */
NTResourceToBlob(const char * id)2035 MagickExport unsigned char *NTResourceToBlob(const char *id)
2036 {
2037 char
2038 directory[MaxTextExtent];
2039
2040 DWORD
2041 length;
2042
2043 HGLOBAL
2044 global;
2045
2046 HMODULE
2047 handle;
2048
2049 HRSRC
2050 resource;
2051
2052 unsigned char
2053 *blob,
2054 *value;
2055
2056 assert(id != (const char *) NULL);
2057 #ifdef MagickLibName
2058 handle=GetModuleHandle(MagickLibName);
2059 #else
2060 FormatString(directory,"%.1024s%.1024s%.1024s",GetClientPath(),
2061 DirectorySeparator,GetClientFilename());
2062 if (IsAccessible(directory))
2063 handle=GetModuleHandle(directory);
2064 else
2065 handle=GetModuleHandle(0);
2066 #endif
2067 if (!handle)
2068 return((unsigned char *) NULL);
2069 /*
2070 Locate a resource matching the specified type and name in the
2071 specified module.
2072 */
2073 resource=FindResource(handle,id,"IMAGEMAGICK");
2074 if (!resource)
2075 {
2076 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
2077 "Tried: windows resource \"%.1024s\"",id);
2078 return((unsigned char *) NULL);
2079 }
2080 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
2081 "Found: windows resource \"%.1024s\"",id);
2082 /*
2083 Load resource into global memory (in WIN32, resources are already
2084 in memory).
2085 */
2086 global=LoadResource(handle,resource);
2087 if (!global)
2088 return((unsigned char *) NULL);
2089 /*
2090 Obtain the size (in bytes) of the specified resource.
2091 */
2092 length=SizeofResource(handle,resource);
2093 /*
2094 Lock the resource in memory (really just dereferences an object
2095 permanently in memory).
2096 */
2097 value=(unsigned char *) LockResource(global);
2098 if (!value)
2099 {
2100 return((unsigned char *) NULL);
2101 }
2102 blob=MagickAllocateMemory(unsigned char *,(size_t) length+1);
2103 if (blob != (unsigned char *) NULL)
2104 {
2105 (void) memcpy(blob,value,length);
2106 blob[length]='\0';
2107 }
2108 return(blob);
2109 }
2110
2111 /*
2112 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2113 % %
2114 % %
2115 % %
2116 + N T s t r e r r o r _ r %
2117 % %
2118 % %
2119 % %
2120 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2121 %
2122 % Method NTstrerror_r formats a returned Windows error code into a
2123 % message string in a thread-safe manner. MagickFail is returned if a
2124 % message could not be found corresponding to the error code, otherwise
2125 % MagickPass is returned.
2126 %
2127 % The format of the NTstrerror_r method is:
2128 %
2129 % MagickPassFail NTstrerror_r(LONG errnum, char *strerrbuf, size_t buflen)
2130 %
2131 % A description of each parameter follows:
2132 %
2133 % o errnum: Windows error number
2134 %
2135 % o strerrbuf: A buffer in which to write the message.
2136 %
2137 % o buflen: The allocation length of the buffer.
2138 %
2139 */
2140 static MagickPassFail
NTstrerror_r(LONG errnum,char * strerrbuf,size_t buflen)2141 NTstrerror_r(LONG errnum, char *strerrbuf, size_t buflen)
2142 {
2143 MagickPassFail
2144 status;
2145
2146 LPVOID
2147 buffer;
2148
2149 status=MagickFail;
2150 if (buflen > 0)
2151 strerrbuf[0]='\0';
2152 if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
2153 FORMAT_MESSAGE_FROM_SYSTEM,NULL,errnum,
2154 MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
2155 (LPTSTR) &buffer,0,NULL))
2156 {
2157 if (strlcpy(strerrbuf,buffer,buflen) < buflen)
2158 {
2159 size_t
2160 index;
2161
2162 for (index=0; strerrbuf[index] != 0; index++)
2163 if (strerrbuf[index] == '\015')
2164 strerrbuf[index]='\0';
2165 status=MagickPass;
2166 }
2167 LocalFree(buffer);
2168 }
2169 return status;
2170 }
2171
2172 /*
2173 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2174 % %
2175 % %
2176 % %
2177 % N T S y s t e m C o m m a n d %
2178 % %
2179 % %
2180 % %
2181 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2182 %
2183 % Method NTSystemComman executes the specified command and waits until it
2184 % terminates. The returned value is the exit status of the command.
2185 %
2186 % The format of the NTSystemComman method is:
2187 %
2188 % int NTSystemComman(const char *command)
2189 %
2190 % A description of each parameter follows:
2191 %
2192 % o command: This string is the command to execute.
2193 %
2194 %
2195 */
NTSystemComman(const char * command)2196 MagickExport int NTSystemComman(const char *command)
2197 {
2198 char
2199 local_command[MaxTextExtent];
2200
2201 DWORD
2202 child_status;
2203
2204 int
2205 status;
2206
2207 PROCESS_INFORMATION
2208 process_info;
2209
2210 STARTUPINFO
2211 startup_info;
2212
2213 unsigned int
2214 background_process;
2215
2216 if (command == (char *) NULL)
2217 return(-1);
2218 GetStartupInfo(&startup_info);
2219 startup_info.dwFlags=STARTF_USESHOWWINDOW;
2220 startup_info.wShowWindow=SW_SHOWMINNOACTIVE;
2221 (void) strlcpy(local_command,command,MaxTextExtent);
2222 background_process=command[strlen(command)-1] == '&';
2223 if (background_process)
2224 local_command[strlen(command)-1]='\0';
2225 if (command[strlen(command)-1] == '|')
2226 local_command[strlen(command)-1]='\0';
2227 else
2228 startup_info.wShowWindow=SW_SHOWDEFAULT;
2229 status=CreateProcess((LPCTSTR) NULL,local_command,
2230 (LPSECURITY_ATTRIBUTES) NULL,(LPSECURITY_ATTRIBUTES) NULL,(BOOL) FALSE,
2231 (DWORD) NORMAL_PRIORITY_CLASS,(LPVOID) NULL,(LPCSTR) NULL,&startup_info,
2232 &process_info);
2233 if (status == 0)
2234 return(-1);
2235 if (background_process)
2236 return(status == 0);
2237
2238 #if 1
2239 // This code has been used for years, but supposedly may
2240 // cause problems in GUIs.
2241 status=WaitForSingleObject(process_info.hProcess,INFINITE);
2242 if (status != WAIT_OBJECT_0)
2243 return (status);
2244 #else
2245 // Following code doesn't work correctly yet
2246 while(1)
2247 {
2248 // Wait for state change or message received
2249 DWORD result=MsgWaitForMultipleObjects(1, &process_info.hProcess, FALSE,
2250 INFINITE, QS_ALLEVENTS);
2251 // Loop if return was due to message received (which we don't care about).
2252 if (result == (WAIT_OBJECT_0+1))
2253 continue;
2254 // If return was due to handle state change, then object is available.
2255 if ((result - WAIT_OBJECT_0) == 0)
2256 break;
2257 }
2258 #endif
2259
2260 status=GetExitCodeProcess(process_info.hProcess,&child_status);
2261 if (status == 0)
2262 return(-1);
2263 CloseHandle(process_info.hProcess);
2264 CloseHandle(process_info.hThread);
2265 return((int) child_status);
2266 }
2267
2268 /*
2269 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2270 % %
2271 % %
2272 % %
2273 % N T U s e r T i m e %
2274 % %
2275 % %
2276 % %
2277 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2278 %
2279 % Method NTUserTime returns the total time the process has been scheduled (i
2280 % seconds) since the last call to StartTimer().
2281 %
2282 % The format of the UserTime method is:
2283 %
2284 % double NTUserTime(void)
2285 %
2286 %
2287 */
NTUserTime(void)2288 MagickExport double NTUserTime(void)
2289 {
2290 DWORD
2291 status;
2292
2293 FILETIME
2294 create_time,
2295 exit_time;
2296
2297 OSVERSIONINFO
2298 OsVersionInfo;
2299
2300 union
2301 {
2302 FILETIME
2303 filetime;
2304
2305 __int64
2306 filetime64;
2307 } kernel_time;
2308
2309 union
2310 {
2311 FILETIME
2312 filetime;
2313
2314 __int64
2315 filetime64;
2316 } user_time;
2317
2318 OsVersionInfo.dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
2319 GetVersionEx(&OsVersionInfo);
2320 if (OsVersionInfo.dwPlatformId != VER_PLATFORM_WIN32_NT)
2321 return(NTElapsedTime());
2322 status=GetProcessTimes(GetCurrentProcess(),&create_time,&exit_time,
2323 &kernel_time.filetime,&user_time.filetime);
2324 if (status != TRUE)
2325 return(0.0);
2326 return((double) 1.0e-7*(kernel_time.filetime64+user_time.filetime64));
2327 }
2328
2329 /*
2330 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2331 % %
2332 % %
2333 % %
2334 % N T W a r n i n g H a n d l e r %
2335 % %
2336 % %
2337 % %
2338 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2339 %
2340 % Method NTWarningHandler displays a warning reason.
2341 %
2342 % The format of the NTWarningHandler method is:
2343 %
2344 % void NTWarningHandler(const ExceptionType warning,const char *reason,
2345 % const char *description)
2346 %
2347 % A description of each parameter follows:
2348 %
2349 % o warning: Specifies the numeric warning category.
2350 %
2351 % o reason: Specifies the reason to display before terminating the
2352 % program.
2353 %
2354 % o description: Specifies any description to the reason.
2355 %
2356 %
2357 */
NTWarningHandler(const ExceptionType warning,const char * reason,const char * description)2358 MagickExport void NTWarningHandler(const ExceptionType warning,
2359 const char *reason,const char *description)
2360 {
2361 char
2362 buffer[2*MaxTextExtent];
2363
2364 ARG_NOT_USED(warning);
2365
2366 if (reason == (char *) NULL)
2367 return;
2368 if (description == (char *) NULL)
2369 FormatString(buffer,"%.1024s: %.1024s.\n",
2370 GetClientName(),reason);
2371 else
2372 FormatString(buffer,"%.1024s: %.1024s (%.1024s).\n",
2373 GetClientName(),reason,description);
2374 (void) MessageBox(NULL,buffer,"GraphicsMagick Warning",MB_OK | MB_TASKMODAL |
2375 MB_SETFOREGROUND | MB_ICONINFORMATION);
2376 }
2377
2378 /*
2379 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2380 % %
2381 % %
2382 % %
2383 % N T f t r u n c a t e %
2384 % %
2385 % %
2386 % %
2387 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2388 %
2389 % Method NTftruncate truncates a file to the specified size. If the file is
2390 % longer than the specified size, it is shortened to the specified size. If
2391 % the file is shorter than the specified size, it is extended to the
2392 % specified size by filling with zeros.
2393 % This is a POSIX compatability function.
2394 %
2395 % The format of the NTftruncate method is:
2396 %
2397 % int NTftruncate(int filedes, off_t length)
2398 %
2399 % A description of each parameter follows:
2400 %
2401 % o status: Zero is returned on successful completion. Otherwise -1
2402 % is returned and errno is set to indicate the error.
2403 %
2404 % o filedes: File descriptor from the _open() call.
2405 %
2406 % o length: Desired file length.
2407 %
2408 */
NTftruncate(int filedes,off_t length)2409 MagickExport int NTftruncate(int filedes, off_t length)
2410 {
2411 int
2412 status;
2413
2414 magick_off_t
2415 current_pos;
2416
2417 status=0;
2418 current_pos=MagickTell(filedes);
2419
2420 /*
2421 Truncate file to size, filling any extension with nulls.
2422 Notice that this interface is limited to 2GB due to its
2423 use of a 'long' offset. Ftruncate also has this shortcoming
2424 if off_t is a 'long'.
2425
2426 A way to support more than 2GB is to use SetFilePointerEx()
2427 to set the file position followed by SetEndOfFile() to set
2428 the file EOF to the current file position. This approach does
2429 not ensure that bytes in the extended portion are null.
2430
2431 The CreateFileMapping() function may also be used to extend a
2432 file's length. The filler byte values are not defined in the
2433 documentation.
2434 */
2435 status=chsize(filedes,length);
2436
2437 /*
2438 It is not documented if _chsize preserves the seek
2439 position, so restore the seek position like ftruncate
2440 does
2441 */
2442 if (!status)
2443 status=MagickSeek(filedes,current_pos,SEEK_SET);
2444 return(status);
2445 }
2446
2447 /*
2448 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2449 % %
2450 % %
2451 % %
2452 + N T m m a p %
2453 % %
2454 % %
2455 % %
2456 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2457 %
2458 % Method NTmmap emulates POSIX mmap. Supports PROT_READ, PROT_WRITE
2459 % protection options, and MAP_SHARED, MAP_PRIVATE, MAP_ANON flags.
2460 % Passing a file descriptor of -1 along with the MAP_ANON flag option returns
2461 % a memory allocation from the system page file with the specified allocated
2462 % length.
2463 %
2464 % The format of the NTmmap method is:
2465 %
2466 % MagickExport void *NTmmap(char *address, size_t length, int protection,
2467 % int flags, int file, magick_off_t offset)
2468 %
2469 %
2470 */
NTmmap(char * address,size_t length,int protection,int flags,int file,magick_off_t offset)2471 MagickExport void *NTmmap(char *address,size_t length,int protection,int flags,
2472 int file,magick_off_t offset)
2473 {
2474 void
2475 *map;
2476
2477 HANDLE
2478 file_handle,
2479 shmem_handle;
2480
2481 DWORD
2482 length_low,
2483 length_high,
2484 offset_low,
2485 offset_high;
2486
2487 DWORD
2488 access_mode=0,
2489 protection_mode=0;
2490
2491 ARG_NOT_USED(address);
2492
2493 map=(void *) NULL;
2494 shmem_handle=INVALID_HANDLE_VALUE;
2495 file_handle=INVALID_HANDLE_VALUE;
2496
2497 offset_low=(DWORD) (offset & 0xFFFFFFFFUL);
2498 offset_high=(DWORD) ((offset >> 32) & 0xFFFFFFFFUL);
2499
2500 length_low=(DWORD) (length & 0xFFFFFFFFUL);
2501 length_high=(DWORD) ((((magick_off_t) length) >> 32) & 0xFFFFFFFFUL);
2502
2503 if (protection & PROT_WRITE)
2504 {
2505 access_mode=FILE_MAP_WRITE;
2506 if (flags & MAP_PRIVATE)
2507 {
2508 // Copy on write (updates are private)
2509 access_mode=FILE_MAP_COPY;
2510 protection_mode=PAGE_WRITECOPY;
2511 }
2512 else
2513 {
2514 // Updates are shared
2515 protection_mode=PAGE_READWRITE;
2516 }
2517 }
2518 else if (protection & PROT_READ)
2519 {
2520 access_mode=FILE_MAP_READ;
2521 protection_mode=PAGE_READONLY;
2522 }
2523
2524 if ((file == -1) && (flags & MAP_ANON))
2525 // Similar to using mmap on /dev/zero to allocate memory from paging area.
2526 file_handle=INVALID_HANDLE_VALUE;
2527 else
2528 file_handle=(HANDLE) _get_osfhandle(file);
2529
2530 shmem_handle=CreateFileMapping(file_handle,0,protection_mode,length_high,
2531 length_low,0);
2532 if (shmem_handle)
2533 {
2534 map=(void *) MapViewOfFile(shmem_handle,access_mode,offset_high,
2535 offset_low,length);
2536 CloseHandle(shmem_handle);
2537 }
2538
2539 if (map == (void *) NULL)
2540 return((void *) MAP_FAILED);
2541 return((void *) ((char *) map));
2542 }
2543
2544 /*
2545 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2546 % %
2547 % %
2548 % %
2549 + N T m s y n c %
2550 % %
2551 % %
2552 % %
2553 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2554 %
2555 % Method NTmsync emulates the Unix msync function except that the flags
2556 % argument is ignored. Windows page sync behaves mostly like MS_SYNC
2557 % except that if the file is accessed over a network, the updates are not
2558 % fully synchronous unless a special flag is provided when the file is
2559 % opened. It is not clear if flushing a range invalidates copy pages
2560 % like Unix msync does.
2561 %
2562 % The format of the NTmsync method is:
2563 %
2564 % int NTmsync(void *addr, size_t len, int flags)
2565 %
2566 % A description of each parameter follows:
2567 %
2568 % o status: Method NTmsync returns 0 on success; otherwise, it
2569 % returns -1 and sets errno to indicate the error.
2570 %
2571 % o addr: The address of the binary large object.
2572 %
2573 % o len: The length of the binary large object.
2574 %
2575 % o flags: Option flags (ignored for Windows)
2576 %
2577 %
2578 */
NTmsync(void * addr,size_t len,int flags)2579 MagickExport int NTmsync(void *addr, size_t len, int flags)
2580 {
2581 ARG_NOT_USED(flags);
2582 if (!FlushViewOfFile(addr,len))
2583 return(-1);
2584 return(0);
2585 }
2586
2587 /*
2588 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2589 % %
2590 % %
2591 % %
2592 % N T o p e n d i r %
2593 % %
2594 % %
2595 % %
2596 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2597 %
2598 % Method NTopendir opens the directory named by filename and associates
2599 % a directory stream with it.
2600 %
2601 % The format of the opendir method is:
2602 %
2603 % DIR *NTopendir(const char *path)
2604 %
2605 % A description of each parameter follows:
2606 %
2607 % o entry: Specifies a pointer to a DIR structure.
2608 %
2609 %
2610 */
NTopendir(const char * path)2611 MagickExport DIR *NTopendir(const char *path)
2612 {
2613 char
2614 file_specification[MaxTextExtent];
2615
2616 DIR
2617 *entry;
2618
2619 assert(path != (char *) NULL);
2620 if (strlcpy(file_specification,path,MaxTextExtent) >= MaxTextExtent)
2621 return (DIR *) NULL;;
2622 if (strlcat(file_specification,DirectorySeparator,MaxTextExtent) >= MaxTextExtent)
2623 return (DIR *) NULL;;
2624 entry=MagickAllocateMemory(DIR *,sizeof(DIR));
2625 if (entry != (DIR *) NULL)
2626 {
2627 entry->firsttime=TRUE;
2628 entry->hSearch=FindFirstFile(file_specification,&entry->Win32FindData);
2629 }
2630 if (entry->hSearch == INVALID_HANDLE_VALUE)
2631 {
2632 if (strlcat(file_specification,"\\*.*",MaxTextExtent) >= MaxTextExtent)
2633 {
2634 MagickFreeMemory(entry);
2635 return (DIR *) NULL;
2636 }
2637 entry->hSearch=FindFirstFile(file_specification,&entry->Win32FindData);
2638 if (entry->hSearch == INVALID_HANDLE_VALUE)
2639 {
2640 MagickFreeMemory(entry);
2641 return (DIR *) NULL;
2642 }
2643 }
2644 return(entry);
2645 }
2646
2647 /*
2648 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2649 % %
2650 % %
2651 % %
2652 % N T r e a d d i r %
2653 % %
2654 % %
2655 % %
2656 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2657 %
2658 % Method NTreaddir returns a pointer to a structure representing the
2659 % directory entry at the current position in the directory stream to
2660 % which entry refers.
2661 %
2662 % The format of the readdir
2663 %
2664 % NTreaddir(entry)
2665 %
2666 % A description of each parameter follows:
2667 %
2668 % o entry: Specifies a pointer to a DIR structure.
2669 %
2670 %
2671 */
NTreaddir(DIR * entry)2672 MagickExport struct dirent *NTreaddir(DIR *entry)
2673 {
2674 int
2675 status;
2676
2677 if (entry == (DIR *) NULL)
2678 return ((struct dirent *) NULL);
2679 if (!entry->firsttime)
2680 {
2681 status=FindNextFile(entry->hSearch,&entry->Win32FindData);
2682 if (status == 0)
2683 return ((struct dirent *) NULL);
2684 }
2685 if (strlcpy(entry->file_info.d_name,entry->Win32FindData.cFileName,
2686 sizeof(entry->file_info.d_name)) >=
2687 sizeof(entry->file_info.d_name))
2688 return ((struct dirent *) NULL);
2689 entry->firsttime=FALSE;
2690 entry->file_info.d_namlen=(int) strlen(entry->file_info.d_name);
2691 return (&entry->file_info);
2692 }
2693
2694 /*
2695 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2696 % %
2697 % %
2698 % %
2699 % N T s e e k d i r %
2700 % %
2701 % %
2702 % %
2703 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2704 %
2705 % Method NTseekdir sets the position of the next NTreaddir() operation
2706 % on the directory stream.
2707 %
2708 % The format of the NTseekdir method is:
2709 %
2710 % void NTseekdir(DIR *entry,long position)
2711 %
2712 % A description of each parameter follows:
2713 %
2714 % o entry: Specifies a pointer to a DIR structure.
2715 %
2716 % o position: specifies the position associated with the directory
2717 % stream.
2718 %
2719 %
2720 %
2721 */
NTseekdir(DIR * entry,long position)2722 MagickExport void NTseekdir(DIR *entry,long position)
2723 {
2724 ARG_NOT_USED(position);
2725 assert(entry != (DIR *) NULL);
2726 }
2727
2728 /*
2729 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2730 % %
2731 % %
2732 % %
2733 % N T t e l l d i r %
2734 % %
2735 % %
2736 % %
2737 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2738 %
2739 % Method NTtelldir returns the current location associated with the
2740 % named directory stream.
2741 %
2742 % The format of the NTtelldir method is:
2743 %
2744 % long NTtelldir(DIR *entry)
2745 %
2746 % A description of each parameter follows:
2747 %
2748 % o entry: Specifies a pointer to a DIR structure.
2749 %
2750 %
2751 */
NTtelldir(DIR * entry)2752 MagickExport long NTtelldir(DIR *entry)
2753 {
2754 assert(entry != (DIR *) NULL);
2755 return(0);
2756 }
2757 #endif
2758