blob: 209dd578dcff1d94dbfd5dfb779748df28717904 [file] [log] [blame]
cristyf7836bf2012-02-20 16:32:47 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% %
7% N N TTTTT %
8% NN N T %
9% N N N T %
10% N NN T %
11% N N T %
12% %
13% %
14% Windows NT Feature Methods for MagickCore %
15% %
16% Software Design %
17% John Cristy %
18% December 1996 %
19% %
20% %
21% Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization %
22% dedicated to making software imaging solutions freely available. %
23% %
24% You may not use this file except in compliance with the License. You may %
25% obtain a copy of the License at %
26% %
27% http://www.imagemagick.org/script/license.php %
28% %
29% Unless required by applicable law or agreed to in writing, software %
30% distributed under the License is distributed on an "AS IS" BASIS, %
31% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
32% See the License for the specific language governing permissions and %
33% limitations under the License. %
34% %
35%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
36%
37%
38*/
39
40/*
41 Include declarations.
42*/
cristy309042f2012-02-20 18:59:35 +000043#include "MagickCore/studio.h"
cristyf7836bf2012-02-20 16:32:47 +000044#if defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__CYGWIN__)
45#define WIN32_LEAN_AND_MEAN
46#define VC_EXTRALEAN
47#include <windows.h>
cristy309042f2012-02-20 18:59:35 +000048#include "MagickCore/cache.h"
49#include "MagickCore/colorspace.h"
50#include "MagickCore/colorspace-private.h"
51#include "MagickCore/draw.h"
52#include "MagickCore/exception.h"
53#include "MagickCore/exception-private.h"
54#include "MagickCore/image-private.h"
55#include "MagickCore/memory_.h"
56#include "MagickCore/monitor.h"
57#include "MagickCore/monitor-private.h"
cristyd2d11ec2012-03-28 13:53:49 +000058#include "MagickCore/nt-base.h"
59#include "MagickCore/nt-base-private.h"
cristy309042f2012-02-20 18:59:35 +000060#include "MagickCore/pixel-accessor.h"
61#include "MagickCore/quantum.h"
62#include "MagickCore/string_.h"
63#include "MagickCore/token.h"
64#include "MagickCore/splay-tree.h"
65#include "MagickCore/utility.h"
cristy2c5fc272012-02-22 01:27:46 +000066#include "MagickCore/nt-base-private.h"
cristyf7836bf2012-02-20 16:32:47 +000067
68/*
69%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
70% %
71% %
72% %
73% C r o p I m a g e T o H B i t m a p %
74% %
75% %
76% %
77%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
78%
79% CropImageToHBITMAP() extracts a specified region of the image and returns
80% it as a Windows HBITMAP. While the same functionality can be accomplished by
81% invoking CropImage() followed by ImageToHBITMAP(), this method is more
82% efficient since it copies pixels directly to the HBITMAP.
83%
84% The format of the CropImageToHBITMAP method is:
85%
86% HBITMAP CropImageToHBITMAP(Image* image,const RectangleInfo *geometry,
87% ExceptionInfo *exception)
88%
89% A description of each parameter follows:
90%
91% o image: the image.
92%
93% o geometry: Define the region of the image to crop with members
94% x, y, width, and height.
95%
96% o exception: return any errors or warnings in this structure.
97%
98*/
99MagickExport void *CropImageToHBITMAP(Image *image,
100 const RectangleInfo *geometry,ExceptionInfo *exception)
101{
102#define CropImageTag "Crop/Image"
103
104 BITMAP
105 bitmap;
106
107 HBITMAP
108 bitmapH;
109
110 HANDLE
111 bitmap_bitsH;
112
113 MagickBooleanType
114 proceed;
115
116 RectangleInfo
117 page;
118
cristy309042f2012-02-20 18:59:35 +0000119 register const Quantum
cristyf7836bf2012-02-20 16:32:47 +0000120 *p;
121
122 register RGBQUAD
123 *q;
124
125 RGBQUAD
126 *bitmap_bits;
127
128 ssize_t
129 y;
130
131 /*
132 Check crop geometry.
133 */
134 assert(image != (const Image *) NULL);
135 assert(image->signature == MagickSignature);
136 if (image->debug != MagickFalse)
137 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
138 assert(geometry != (const RectangleInfo *) NULL);
139 assert(exception != (ExceptionInfo *) NULL);
140 assert(exception->signature == MagickSignature);
141 if (((geometry->x+(ssize_t) geometry->width) < 0) ||
142 ((geometry->y+(ssize_t) geometry->height) < 0) ||
143 (geometry->x >= (ssize_t) image->columns) ||
144 (geometry->y >= (ssize_t) image->rows))
145 ThrowImageException(OptionError,"GeometryDoesNotContainImage");
146 page=(*geometry);
147 if ((page.x+(ssize_t) page.width) > (ssize_t) image->columns)
148 page.width=image->columns-page.x;
149 if ((page.y+(ssize_t) page.height) > (ssize_t) image->rows)
150 page.height=image->rows-page.y;
151 if (page.x < 0)
152 {
153 page.width+=page.x;
154 page.x=0;
155 }
156 if (page.y < 0)
157 {
158 page.height+=page.y;
159 page.y=0;
160 }
161
162 if ((page.width == 0) || (page.height == 0))
163 ThrowImageException(OptionError,"GeometryDimensionsAreZero");
164 /*
165 Initialize crop image attributes.
166 */
167 bitmap.bmType = 0;
168 bitmap.bmWidth = (LONG) page.width;
169 bitmap.bmHeight = (LONG) page.height;
170 bitmap.bmWidthBytes = bitmap.bmWidth * 4;
171 bitmap.bmPlanes = 1;
172 bitmap.bmBitsPixel = 32;
173 bitmap.bmBits = NULL;
174
175 bitmap_bitsH=(HANDLE) GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE,page.width*
176 page.height*bitmap.bmBitsPixel);
177 if (bitmap_bitsH == NULL)
178 return(NULL);
179 bitmap_bits=(RGBQUAD *) GlobalLock((HGLOBAL) bitmap_bitsH);
180 if ( bitmap.bmBits == NULL )
181 bitmap.bmBits = bitmap_bits;
cristy0bd9ced2012-06-20 14:48:22 +0000182 if ((IssRGBColorspace(image->colorspace) == MagickFalse) &&
183 (IsGrayColorspace(image->colorspace) == MagickFalse))
cristy309042f2012-02-20 18:59:35 +0000184 TransformImageColorspace(image,sRGBColorspace,exception);
cristyf7836bf2012-02-20 16:32:47 +0000185 /*
186 Extract crop image.
187 */
188 q=bitmap_bits;
189 for (y=0; y < (ssize_t) page.height; y++)
190 {
cristy309042f2012-02-20 18:59:35 +0000191 register ssize_t
192 x;
193
cristyf7836bf2012-02-20 16:32:47 +0000194 p=GetVirtualPixels(image,page.x,page.y+y,page.width,1,exception);
cristy309042f2012-02-20 18:59:35 +0000195 if (p == (const Quantum *) NULL)
cristyf7836bf2012-02-20 16:32:47 +0000196 break;
197
cristy309042f2012-02-20 18:59:35 +0000198 /* Transfer pixels, scaling to Quantum */
199 for( x=(ssize_t) page.width ; x> 0 ; x-- )
200 {
201 q->rgbRed = ScaleQuantumToChar(GetPixelRed(image,p));
202 q->rgbGreen = ScaleQuantumToChar(GetPixelGreen(image,p));
203 q->rgbBlue = ScaleQuantumToChar(GetPixelBlue(image,p));
204 q->rgbReserved = 0;
205 p+=GetPixelChannels(image);
206 q++;
207 }
cristyf7836bf2012-02-20 16:32:47 +0000208 proceed=SetImageProgress(image,CropImageTag,y,page.height);
209 if (proceed == MagickFalse)
210 break;
211 }
212 if (y < (ssize_t) page.height)
213 {
214 GlobalUnlock((HGLOBAL) bitmap_bitsH);
215 GlobalFree((HGLOBAL) bitmap_bitsH);
216 return((void *) NULL);
217 }
218 bitmap.bmBits=bitmap_bits;
219 bitmapH=CreateBitmapIndirect(&bitmap);
220 GlobalUnlock((HGLOBAL) bitmap_bitsH);
221 GlobalFree((HGLOBAL) bitmap_bitsH);
222 return((void *) bitmapH);
223}
224
225/*
226%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
227% %
228% %
229% %
230% I s M a g i c k C o n f l i c t %
231% %
232% %
233% %
234%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
235%
236% IsMagickConflict() returns true if the image format conflicts with a logical
237% drive (.e.g. X:).
238%
239% The format of the IsMagickConflict method is:
240%
241% MagickBooleanType IsMagickConflict(const char *magick)
242%
243% A description of each parameter follows:
244%
245% o magick: Specifies the image format.
246%
247*/
248MagickExport MagickBooleanType NTIsMagickConflict(const char *magick)
249{
250 MagickBooleanType
251 status;
252
253 assert(magick != (char *) NULL);
254 if (strlen(magick) > 1)
255 return(MagickFalse);
256 status=(GetLogicalDrives() & (1 << ((toupper((int) (*magick)))-'A'))) != 0 ?
257 MagickTrue : MagickFalse;
258 return(status);
259}
260
261/*
262%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
263% %
264% %
265% %
266+ N T G e t T y pe L i s t %
267% %
268% %
269% %
270%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
271%
272% NTLoadTypeLists() loads a Windows TrueType fonts.
273%
274% The format of the NTLoadTypeLists method is:
275%
276% MagickBooleanType NTLoadTypeLists(SplayTreeInfo *type_list)
277%
278% A description of each parameter follows:
279%
280% o type_list: A linked list of fonts.
281%
282*/
283MagickExport MagickBooleanType NTLoadTypeLists(SplayTreeInfo *type_list,
284 ExceptionInfo *exception)
285{
286 HKEY
287 reg_key = (HKEY) INVALID_HANDLE_VALUE;
288
289 LONG
290 res;
291
292
293 int
294 list_entries = 0;
295
296 char
297 buffer[MaxTextExtent],
298 system_root[MaxTextExtent],
299 font_root[MaxTextExtent];
300
301 DWORD
302 type,
303 system_root_length;
304
305 MagickBooleanType
306 status;
307
308 /*
309 Try to find the right Windows*\CurrentVersion key, the SystemRoot and
310 then the Fonts key
311 */
312 res = RegOpenKeyExA (HKEY_LOCAL_MACHINE,
313 "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", 0, KEY_READ, &reg_key);
314 if (res == ERROR_SUCCESS) {
315 system_root_length=sizeof(system_root)-1;
316 res = RegQueryValueExA(reg_key,"SystemRoot",NULL, &type,
317 (BYTE*) system_root, &system_root_length);
318 }
319 if (res != ERROR_SUCCESS) {
320 res = RegOpenKeyExA (HKEY_LOCAL_MACHINE,
321 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion", 0, KEY_READ, &reg_key);
322 if (res == ERROR_SUCCESS) {
323 system_root_length=sizeof(system_root)-1;
324 res = RegQueryValueExA(reg_key,"SystemRoot",NULL, &type,
325 (BYTE*)system_root, &system_root_length);
326 }
327 }
328 if (res == ERROR_SUCCESS)
329 res = RegOpenKeyExA (reg_key, "Fonts",0, KEY_READ, &reg_key);
330 if (res != ERROR_SUCCESS)
331 return(MagickFalse);
332 *font_root='\0';
333 (void) CopyMagickString(buffer,system_root,MaxTextExtent);
334 (void) ConcatenateMagickString(buffer,"\\fonts\\arial.ttf",MaxTextExtent);
335 if (IsPathAccessible(buffer) != MagickFalse)
336 {
337 (void) CopyMagickString(font_root,system_root,MaxTextExtent);
338 (void) ConcatenateMagickString(font_root,"\\fonts\\",MaxTextExtent);
339 }
340 else
341 {
342 (void) CopyMagickString(font_root,system_root,MaxTextExtent);
343 (void) ConcatenateMagickString(font_root,"\\",MaxTextExtent);
344 }
345
346 {
347 TypeInfo
348 *type_info;
349
350 DWORD
351 registry_index = 0,
352 type,
353 value_data_size,
354 value_name_length;
355
356 char
357 value_data[MaxTextExtent],
358 value_name[MaxTextExtent];
359
360 res = ERROR_SUCCESS;
361
362 while (res != ERROR_NO_MORE_ITEMS)
363 {
364 char
365 *family_extent,
366 token[MaxTextExtent],
367 *pos,
368 *q;
369
370 value_name_length = sizeof(value_name) - 1;
371 value_data_size = sizeof(value_data) - 1;
372 res = RegEnumValueA ( reg_key, registry_index, value_name,
373 &value_name_length, 0, &type, (BYTE*)value_data, &value_data_size);
374 registry_index++;
375 if (res != ERROR_SUCCESS)
376 continue;
377 if ( (pos = strstr(value_name, " (TrueType)")) == (char*) NULL )
378 continue;
379 *pos='\0'; /* Remove (TrueType) from string */
380
381 type_info=(TypeInfo *) AcquireMagickMemory(sizeof(*type_info));
382 if (type_info == (TypeInfo *) NULL)
383 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
384 (void) ResetMagickMemory(type_info,0,sizeof(TypeInfo));
385
386 type_info->path=ConstantString("Windows Fonts");
387 type_info->signature=MagickSignature;
388
389 /* Name */
390 (void) CopyMagickString(buffer,value_name,MaxTextExtent);
391 for(pos = buffer; *pos != 0 ; pos++)
392 if (*pos == ' ')
393 *pos = '-';
394 type_info->name=ConstantString(buffer);
395
396 /* Fullname */
397 type_info->description=ConstantString(value_name);
398
399 /* Format */
400 type_info->format=ConstantString("truetype");
401
402 /* Glyphs */
403 if (strchr(value_data,'\\') != (char *) NULL)
404 (void) CopyMagickString(buffer,value_data,MaxTextExtent);
405 else
406 {
407 (void) CopyMagickString(buffer,font_root,MaxTextExtent);
408 (void) ConcatenateMagickString(buffer,value_data,MaxTextExtent);
409 }
410
411 LocaleLower(buffer);
412 type_info->glyphs=ConstantString(buffer);
413
414 type_info->stretch=NormalStretch;
415 type_info->style=NormalStyle;
416 type_info->weight=400;
417
418 /* Some fonts are known to require special encodings */
419 if ( (LocaleCompare(type_info->name, "Symbol") == 0 ) ||
420 (LocaleCompare(type_info->name, "Wingdings") == 0 ) ||
421 (LocaleCompare(type_info->name, "Wingdings-2") == 0 ) ||
422 (LocaleCompare(type_info->name, "Wingdings-3") == 0 ) )
423 type_info->encoding=ConstantString("AppleRoman");
424
425 family_extent=value_name;
426
427 for (q=value_name; *q != '\0'; )
428 {
429 GetMagickToken(q,(const char **) &q,token);
430 if (*token == '\0')
431 break;
432
433 if (LocaleCompare(token,"Italic") == 0)
434 {
435 type_info->style=ItalicStyle;
436 }
437
438 else if (LocaleCompare(token,"Oblique") == 0)
439 {
440 type_info->style=ObliqueStyle;
441 }
442
443 else if (LocaleCompare(token,"Bold") == 0)
444 {
445 type_info->weight=700;
446 }
447
448 else if (LocaleCompare(token,"Thin") == 0)
449 {
450 type_info->weight=100;
451 }
452
453 else if ( (LocaleCompare(token,"ExtraLight") == 0) ||
454 (LocaleCompare(token,"UltraLight") == 0) )
455 {
456 type_info->weight=200;
457 }
458
459 else if (LocaleCompare(token,"Light") == 0)
460 {
461 type_info->weight=300;
462 }
463
464 else if ( (LocaleCompare(token,"Normal") == 0) ||
465 (LocaleCompare(token,"Regular") == 0) )
466 {
467 type_info->weight=400;
468 }
469
470 else if (LocaleCompare(token,"Medium") == 0)
471 {
472 type_info->weight=500;
473 }
474
475 else if ( (LocaleCompare(token,"SemiBold") == 0) ||
476 (LocaleCompare(token,"DemiBold") == 0) )
477 {
478 type_info->weight=600;
479 }
480
481 else if ( (LocaleCompare(token,"ExtraBold") == 0) ||
482 (LocaleCompare(token,"UltraBold") == 0) )
483 {
484 type_info->weight=800;
485 }
486
487 else if ( (LocaleCompare(token,"Heavy") == 0) ||
488 (LocaleCompare(token,"Black") == 0) )
489 {
490 type_info->weight=900;
491 }
492
493 else if (LocaleCompare(token,"Condensed") == 0)
494 {
495 type_info->stretch = CondensedStretch;
496 }
497
498 else if (LocaleCompare(token,"Expanded") == 0)
499 {
500 type_info->stretch = ExpandedStretch;
501 }
502
503 else if (LocaleCompare(token,"ExtraCondensed") == 0)
504 {
505 type_info->stretch = ExtraCondensedStretch;
506 }
507
508 else if (LocaleCompare(token,"ExtraExpanded") == 0)
509 {
510 type_info->stretch = ExtraExpandedStretch;
511 }
512
513 else if (LocaleCompare(token,"SemiCondensed") == 0)
514 {
515 type_info->stretch = SemiCondensedStretch;
516 }
517
518 else if (LocaleCompare(token,"SemiExpanded") == 0)
519 {
520 type_info->stretch = SemiExpandedStretch;
521 }
522
523 else if (LocaleCompare(token,"UltraCondensed") == 0)
524 {
525 type_info->stretch = UltraCondensedStretch;
526 }
527
528 else if (LocaleCompare(token,"UltraExpanded") == 0)
529 {
530 type_info->stretch = UltraExpandedStretch;
531 }
532
533 else
534 {
535 family_extent=q;
536 }
537 }
538
539 (void) CopyMagickString(buffer,value_name,family_extent-value_name+1);
540 StripString(buffer);
541 type_info->family=ConstantString(buffer);
542
543 list_entries++;
544 status=AddValueToSplayTree(type_list,ConstantString(type_info->name),
545 type_info);
546 if (status == MagickFalse)
547 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +0000548 ResourceLimitError,"MemoryAllocationFailed","'%s'",type_info->name);
cristyf7836bf2012-02-20 16:32:47 +0000549 }
550 }
551 RegCloseKey ( reg_key );
552 return(MagickTrue);
553}
554
555/*
556%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
557% %
558% %
559% %
560% I m a g e T o H B i t m a p %
561% %
562% %
563% %
564%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
565%
566% ImageToHBITMAP() creates a Windows HBITMAP from an image.
567%
568% The format of the ImageToHBITMAP method is:
569%
570% HBITMAP ImageToHBITMAP(Image *image,Exceptioninfo *exception)
571%
572% A description of each parameter follows:
573%
574% o image: the image to convert.
575%
576*/
577MagickExport void *ImageToHBITMAP(Image *image,ExceptionInfo *exception)
578{
579 BITMAP
580 bitmap;
581
582 HANDLE
583 bitmap_bitsH;
584
585 HBITMAP
586 bitmapH;
587
588 register ssize_t
589 x;
590
cristy309042f2012-02-20 18:59:35 +0000591 register const Quantum
cristyf7836bf2012-02-20 16:32:47 +0000592 *p;
593
594 register RGBQUAD
595 *q;
596
597 RGBQUAD
598 *bitmap_bits;
599
600 size_t
601 length;
602
603 ssize_t
604 y;
605
606 (void) ResetMagickMemory(&bitmap,0,sizeof(bitmap));
607 bitmap.bmType=0;
608 bitmap.bmWidth=(LONG) image->columns;
609 bitmap.bmHeight=(LONG) image->rows;
610 bitmap.bmWidthBytes=4*bitmap.bmWidth;
611 bitmap.bmPlanes=1;
612 bitmap.bmBitsPixel=32;
613 bitmap.bmBits=NULL;
614 length=bitmap.bmWidthBytes*bitmap.bmHeight;
615 bitmap_bitsH=(HANDLE) GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE,length);
616 if (bitmap_bitsH == NULL)
617 {
618 char
619 *message;
620
621 message=GetExceptionMessage(errno);
622 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +0000623 ResourceLimitError,"MemoryAllocationFailed","'%s'",message);
cristyf7836bf2012-02-20 16:32:47 +0000624 message=DestroyString(message);
625 return(NULL);
626 }
627 bitmap_bits=(RGBQUAD *) GlobalLock((HGLOBAL) bitmap_bitsH);
628 q=bitmap_bits;
629 if (bitmap.bmBits == NULL)
630 bitmap.bmBits=bitmap_bits;
cristy309042f2012-02-20 18:59:35 +0000631 (void) TransformImageColorspace(image,sRGBColorspace,exception);
cristyf7836bf2012-02-20 16:32:47 +0000632 for (y=0; y < (ssize_t) image->rows; y++)
633 {
634 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy309042f2012-02-20 18:59:35 +0000635 if (p == (const Quantum *) NULL)
cristyf7836bf2012-02-20 16:32:47 +0000636 break;
637 for (x=0; x < (ssize_t) image->columns; x++)
638 {
cristy309042f2012-02-20 18:59:35 +0000639 q->rgbRed=ScaleQuantumToChar(GetPixelRed(image,p));
640 q->rgbGreen=ScaleQuantumToChar(GetPixelGreen(image,p));
641 q->rgbBlue=ScaleQuantumToChar(GetPixelBlue(image,p));
cristyf7836bf2012-02-20 16:32:47 +0000642 q->rgbReserved=0;
cristy309042f2012-02-20 18:59:35 +0000643 p+=GetPixelChannels(image);
cristyf7836bf2012-02-20 16:32:47 +0000644 q++;
645 }
646 }
647 bitmap.bmBits=bitmap_bits;
648 bitmapH=CreateBitmapIndirect(&bitmap);
649 if (bitmapH == NULL)
650 {
651 char
652 *message;
653
654 message=GetExceptionMessage(errno);
655 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +0000656 ResourceLimitError,"MemoryAllocationFailed","'%s'",message);
cristyf7836bf2012-02-20 16:32:47 +0000657 message=DestroyString(message);
658 }
659 GlobalUnlock((HGLOBAL) bitmap_bitsH);
660 GlobalFree((HGLOBAL) bitmap_bitsH);
661 return((void *) bitmapH);
662}
663
664#endif