File: winceextra.pp

package info (click to toggle)
lazarus 2.0.0%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 214,460 kB
  • sloc: pascal: 1,862,622; xml: 265,709; cpp: 56,595; sh: 3,008; java: 609; makefile: 535; perl: 297; sql: 222; ansic: 137
file content (750 lines) | stat: -rw-r--r-- 23,780 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
{
 *****************************************************************************
 *                            WinCEWinApiEmu.pp                              *
 *                            -----------------                              *
 * Extra WinCE code that's not in the RTL or present on all WinCE versions.  *
 *                                                                           *
 *****************************************************************************

 *****************************************************************************
  This file is part of the Lazarus Component Library (LCL)

  See the file COPYING.modifiedLGPL.txt, included in this distribution,
  for details about the license.
 *****************************************************************************

  Author: Roozbeh GHolizadeh
          Marc Weustink

  Abstract:
    Missing and useful windows api are defined and emulated here.
    Not all functionalities are present,but only those neccessary for lcl to function.
}
unit WinCEExtra;

{$mode objfpc}{$H+}

interface

uses
  LCLType, LCLIntf, {keep both before windows}
  Windows, Classes, SysUtils, Maps, GraphType;

type
  DrawStateProc = function(
    dc:HDC;         // handle to device context
    ldata: LPARAM;  // image information
    wData: WPARAM;  // more image information
    cx: integer;    // image width
    cy: integer     // image height  
  ) : boolean;

const
  { State type }
  DSS_NORMAL    = $0000;
  DSS_UNION     = $0010;  { Gray string appearance }
  DSS_DISABLED  = $0020;
  DSS_MONO      = $0080;
  DSS_RIGHT     = $8000;
  DSS_DEFAULT   =$0040;  { Make it bold }
  DSS_HIDEPREFIX=$0200;
  DSS_PREFIXONLY=$0400;
  
  { missing progress bar styles }
  PBS_SMOOTH=01;
  PBS_VERTICAL=04;
  PBM_SETRANGE32=WM_USER+6;
  
  { missing listview styles}
  LVS_EX_LABELTIP         = $00004000;
  
  { missing messages }

  WM_HIBERNATE = $03FF;


function DrawState(dc:HDC ; hbr : HBRUSH ; func: DRAWSTATEPROC ; lp:LPARAM; wp:WPARAM;x,y,cx,cy:integer;flags:UINT) : boolean;
function GetTopWindow(hWnd:HWND):HWND;

// missing imagelist macros and constants

const
// image list copy flags
  ILCF_MOVE = $00000000;
  ILCF_SWAP = $00000001;

{$ifdef win32}
function ImageList_Copy(himlDst: HIMAGELIST; iDst: longint; himlSrc: HIMAGELIST; Src: longint; uFlags: UINT): BOOL; stdcall; external 'comctl32';
{$else}
function ImageList_Copy(himlDst: HIMAGELIST; iDst: longint; himlSrc: HIMAGELIST; Src: longint; uFlags: UINT): BOOL; cdecl; external KernelDLL;
{$endif}

const
  // BlendOp flags
  AC_SRC_OVER = $00;
  // AlphaFormat flags
  AC_SRC_ALPHA = $01;

var
  // AlphaBlend is only defined for CE5 and up
  // load dynamic and use ownfunction if not defined
  AlphaBlend: function(hdcDest: HDC; nXOriginDest, nYOriginDest, nWidthDest, nHeightDest: Integer; hdcSrc: HDC; nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc: Integer; blendFunction: TBlendFunction): BOOL; cdecl;

  // SHSendBackToFocusWindow should be available since a long time, but in practice some
  // devices don't have it in their aygshell.dll library
  // see:
  SHSendBackToFocusWindow: procedure(uMsg: UINT; wp: WPARAM; lp: LPARAM); cdecl;
  // For reference the previous static loading:
  //{$ifdef wince}
  //procedure SHSendBackToFocusWindow(uMsg: UINT; wp: WPARAM; lp: LPARAM); cdecl; external 'aygshell' index 97;
  //{$endif}

implementation

uses
  WinCeProc;
  
const
  wPattern55AA: array[1..8] of word = ($5555, $aaaa, $5555, $aaaa, $5555, $aaaa, $5555, $aaaa);

function GetTopWindow(hWnd:HWND):HWND;
begin
  Result := GetWindow(hWnd,GW_CHILD);
end;


{ Wine sources - www.winehq.com - mostly used for emulating DrawState functions }
function DrawStateJam(dc:HDC; opcode:UINT; func: DrawStateProc; lp:LPARAM; wp: WPARAM; rc:LPRECT; dtflags: UINT): boolean;
var
  memdc: HDC;
  hbmsave: HBITMAP;
  cx,cy: integer;
begin
  cx := rc^.Right - rc^.left;
  cy := rc^.bottom - rc^.top;
  
  case opcode of
    DST_TEXT, DST_PREFIXTEXT:
      Result := DrawTextW(dc, PWideChar(lp), wp,
       {$ifdef win32}rc^{$else}rc{$endif}, dtflags) <> 0;
  
    DST_ICON:
      Result := DrawIcon(dc, rc^.left, rc^.top, lp);
  
    DST_BITMAP: begin
      memdc := CreateCompatibleDC(dc);
      if memdc = 0 then Exit(False);
      
      hbmsave := SelectObject(memdc, lp);
      if hbmsave = 0 then
      begin
        DeleteDC(memdc);
        Exit(False);
      end;
      
      Result := BitBlt(dc, rc^.left, rc^.top, cx, cy, memdc, 0, 0, SRCCOPY);
      SelectObject(memdc, hbmsave);
      DeleteDC(memdc);
    end;
  
    DST_COMPLEX: begin
      if func <> nil then
      begin
        { DRAWSTATEPROC assumes that it draws at the center of coordinates  }
        //OffsetViewportOrgEx(dc, rc^.left, rc^.top, nil);
        Result := func(dc, lp, wp, cx, cy);
        
        { Restore origin }
        //OffsetViewportOrgEx(dc, -rc^.left, -rc^.top, nil);
      end 
      else Result := False;
    end;        
  else  
    Result := False;
  end;
end;


{$goto on} // TODO: remove goto

function DrawState(dc: HDC; hbr: HBRUSH; func: DRAWSTATEPROC; lp:LPARAM; wp:WPARAM; x, y, cx, cy: integer; flags: UINT): boolean;
label
  cleanup;
var
  hbm,hbmsave :HBITMAP;
  hfsave : HFONT;
  hbsave,hbrtmp : HBRUSH;
  memdc : HDC;
  rc:TRECT;
  dtflags:UINT;
  opcode:UINT;
  len:integer;
  tmp : boolean;
  s:SIZE;
  //ici:^CURSORICONINFO;
  bm:BITMAP;
  fg, bg : COLORREF;
  
  h55AABrush : HBRUSH;
  h55AABitmap: HBITMAP;
  
begin
  Result := False; 
  hbrtmp := 0;
  dtflags := DT_NOCLIP;
  opcode := flags and $f;
  len := wp;

  if  ((opcode = DST_TEXT) or (opcode = DST_PREFIXTEXT)) and (len=0) 
  then len := length(widestring(PWideChar(lp))); // The string is '\0' terminated 

  { Find out what size the image has if not given by caller }
  if (cx=0) or (cy=0) then
  begin
    case opcode of
      DST_TEXT, DST_PREFIXTEXT:
        begin
          if not GetTextExtentPoint32W(dc, PWideChar(lp), len, s)
          then Exit;
        end;

      {DST_ICON:
        begin
          ici = (CURSORICONINFO *)GlobalLock16((HGLOBAL16)lp);
          if(!ici) then return false;
          s.cx = ici->nWidth;
          s.cy = ici->nHeight;
          GlobalUnlock16((HGLOBAL16)lp);
        end;}

      DST_BITMAP:
        begin
          if GetObject(lp, sizeof(bm), @bm) = 0 
          then Exit;
          s.cx := bm.bmWidth;
          s.cy := bm.bmHeight;
        end;

      DST_COMPLEX: {/* cx and cy must be set in this mode */}
        Exit;
    end;

    if cx = 0 then cx := s.cx;
    if cy = 0 then cy := s.cy;
  end;

  rc.left   := x;
  rc.top    := y;
  rc.right  := x + cx;
  rc.bottom := y + cy;

  if (flags and DSS_RIGHT) <> 0 { This one is not documented in the win32.hlp file }
  then dtflags := dtflags or DT_RIGHT;
  
  if opcode = DST_TEXT 
  then dtflags := dtflags or DT_NOPREFIX;

  { For DSS_NORMAL we just jam in the image and return }
  if (flags and $7ff0) = DSS_NORMAL 
  then Exit(DrawStateJam(dc, opcode, func, lp, len, @rc, dtflags));

  { For all other states we need to convert the image to B/W in a local bitmap
    before it is displayed }
  fg := SetTextColor(dc, RGB(0, 0, 0));
  bg := SetBkColor(dc, RGB(255, 255, 255));
  hbm := 0;
  hbmsave := 0;
  memdc := 0;
  hbsave := 0;

  { From here on we must use "goto cleanup" when something goes wrong }
  // MWE: you can also use an exception block for this.

  hbm := CreateBitmap(cx, cy, 1, 1, nil);
  if hbm = 0 then goto cleanup;
  
  memdc := CreateCompatibleDC(dc);
  if memdc = 0 then goto cleanup;
  
  hbmsave := SelectObject(memdc, hbm);
  if hbmsave = 0 then goto cleanup;
  
  rc.top := 0;
  rc.left := 0;
  rc.right := cx;
  rc.bottom := cy;
  if FillRect(memdc, rc, GetStockObject(WHITE_BRUSH)) = 0 then goto cleanup;
  
  SetBkColor(memdc, RGB(255, 255, 255));
  SetTextColor(memdc, RGB(0, 0, 0));
  hfsave := SelectObject(memdc, GetCurrentObject(dc, OBJ_FONT));

  { DST_COMPLEX may draw text as well,
    so we must be sure that correct font is selected }
  if (hfsave = 0) and (opcode <= DST_PREFIXTEXT) then goto cleanup;
  tmp := DrawStateJam(memdc, opcode, func, lp, len, @rc, dtflags);
  if hfsave <> 0 then SelectObject(memdc, hfsave);
  if not tmp then goto cleanup;

  { This state cause the image to be dithered }
  if (flags and DSS_UNION) <> 0 then
  begin
    h55AABitmap := CreateBitmap( 8, 8, 1, 1, @wPattern55AA);
    h55AABrush := CreatePatternBrush(h55AABitmap);
    hbsave := SelectObject(memdc, h55AABrush);
    if hbsave = 0 
    then begin
      DeleteObject(h55AABrush);
      DeleteObject(h55AABitmap);
      goto cleanup;
    end;
    
    tmp := PatBlt(memdc, 0, 0, cx, cy, $00FA0089);
    SelectObject(memdc, hbsave);
    DeleteObject(h55AABrush);
    DeleteObject(h55AABitmap);
    if not tmp then goto cleanup;
  end;

  if (flags and DSS_DISABLED) <> 0 
  then
     hbrtmp := CreateSolidBrush(LCLIntf.GetSysColor(COLOR_3DHILIGHT))
  else if (flags and DSS_DEFAULT) <> 0 
  then
     hbrtmp := CreateSolidBrush(LCLIntf.GetSysColor(COLOR_3DSHADOW));

  { Draw light or dark shadow }
  if (flags and (DSS_DISABLED or DSS_DEFAULT)) <> 0 then
  begin
    if hbrtmp = 0 then goto cleanup;
    hbsave := SelectObject(dc, hbrtmp);
    if hbsave = 0 then goto cleanup;
    if not BitBlt(dc, x+1, y+1, cx, cy, memdc, 0, 0, $00B8074A)  then goto cleanup;
    SelectObject(dc, hbsave);
    DeleteObject(hbrtmp);
    hbrtmp := 0;
  end;

  if (flags and DSS_DISABLED) <> 0 then
  begin
    hbrtmp := CreateSolidBrush(LCLIntf.GetSysColor(COLOR_3DSHADOW));
    hbr := hbrtmp;
    if hbrtmp = 0 then goto cleanup;
  end
  else begin
    if hbr = 0 
    then hbr := GetStockObject(BLACK_BRUSH);
  end;

  hbsave := SelectObject(dc, hbr);

  if not BitBlt(dc, x, y, cx, cy, memdc, 0, 0, $00B8074A) then goto cleanup;

  Result := True;

cleanup:
  SetTextColor(dc, fg);
  SetBkColor(dc, bg);

  if(hbsave<>0)  then SelectObject(dc, hbsave);
  if(hbmsave<>0) then SelectObject(memdc, hbmsave);
  if(hbrtmp<>0)  then DeleteObject(hbrtmp);
  if(hbm<>0)     then DeleteObject(hbm);
  if(memdc<>0)   then DeleteDC(memdc);
end;

function _AlphaBlend(hdcDest: HDC; nXOriginDest, nYOriginDest, nWidthDest, nHeightDest: Integer; hdcSrc: HDC; nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc: Integer; blendFunction: TBlendFunction): BOOL; cdecl;
var
  SCA: Byte absolute blendFunction.SourceConstantAlpha;
  
  R: TRect;
  DC, TmpDC: HDC;
  OldBmp, OldTmpBmp, SrcBmp, DstBmp, TmpBmp, AlphaBmp: HBITMAP;
  StretchSrc: Boolean;
  SrcSection, DstSection: TDIBSection;
  Info: record
    Header: TBitmapInfoHeader;
    Colors: array[0..3] of Cardinal; // reserve extra color for colormasks
  end;

  SrcBytesPtr, DstBytesPtr, TmpBytesPtr, AlphaBytesPtr: Pointer;
  SrcLinePtr, DstLinePtr: PByte;
  CleanupSrc, CleanupSrcPtr, CleanupDst, CleanupAlpha: Boolean;
  SrcSize: Cardinal;
  SrcPixelBytes, DstPixelBytes: Byte;
  SrcRowStride, DstRowStride: Integer;

  X, Y: Integer;
  SrcRGBA, TmpRGBA, DstRGBA: PRGBAQuad;
  SrcAlpha: PByte;
begin
  if nXOriginSrc < 0 then Exit(False);
  if nYOriginSrc < 0 then Exit(False);
  if nWidthSrc < 0 then Exit(False);
  if nHeightSrc < 0 then Exit(False);
  if nWidthDest < 0 then Exit(False);
  if nHeightDest < 0 then Exit(False);
  
  if blendFunction.SourceConstantAlpha = 0
  then Exit(True); // nothing to do

  if (blendFunction.AlphaFormat = 0)
  and (blendFunction.SourceConstantAlpha = 255)
  then begin
    // simple strechblt
    Result := StretchBlt(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest, hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc, SRCCOPY);
    Exit;
  end;

  // get source info, atleast bitmap, section if available
  SrcBmp := GetCurrentObject(hdcSrc, OBJ_BITMAP);
  if GetObject(SrcBmp, SizeOf(SrcSection), @SrcSection) = 0 then Exit(False);
  if nXOriginSrc + nWidthSrc > SrcSection.dsBm.bmWidth then Exit(False);
  if nYOriginSrc + nHeightSrc > SrcSection.dsBm.bmHeight then Exit(False);
  
  if (blendFunction.AlphaFormat = AC_SRC_ALPHA) and (SrcSection.dsBm.bmBitsPixel <> 32) then Exit(False); // invalid

  // get destination info, atleast bitmap, section if available
  DstBmp := GetCurrentObject(hdcDest, OBJ_BITMAP);
  if (DstBmp = 0) or (GetObject(DstBmp, SizeOf(DstSection), @DstSection) = 0)
  then begin
    // GetCurrentObject can only be used on memory devices,
    // so fill in some values manually
    DstSection.dsBm.bmWidth := GetDeviceCaps(hdcDest, HORZRES);
    DstSection.dsBm.bmHeight := GetDeviceCaps(hdcDest, VERTRES);
    DstSection.dsBm.bmBitsPixel := GetDeviceCaps(hdcDest, BITSPIXEL);
  end;

  // docs doesn't require dest retangle inside dest.
  // however if dest rect is outside the destination, we're done here
  if nXOriginDest + nWidthDest < 0 then Exit(True);
  if nYOriginDest + nHeightDest < 0 then Exit(True);
  if nXOriginDest >= DstSection.dsBm.bmWidth then Exit(True);
  if nYOriginDest >= DstSection.dsBm.bmHeight then Exit(True);
  
  // setup info shared by alpha, source and destination bytes
  FillChar(Info, sizeof(Info), 0);
  Info.Header.biSize := sizeof(Windows.TBitmapInfoHeader);
  Info.Header.biWidth := nWidthDest;
  Info.Header.biHeight := -nHeightDest; // top down
  Info.Header.biPlanes := 1;
  Info.Header.biBitCount := 32;
  Info.Header.biSizeImage := nWidthDest * nHeightDest * 4;
  Info.Header.biCompression := BI_BITFIELDS;
  // when 24bpp, CE only supports B8G8R8 encoding
  Info.Colors[0] := $FF0000; {le-red}
  Info.Colors[1] := $00FF00; {le-green}
  Info.Colors[2] := $0000FF; {le-blue}

  StretchSrc := (nWidthDest <> nWidthSrc) or (nHeightDest <> nHeightSrc);
  if StretchSrc
  then begin
    // we need to strech the source
    
    // create alphabmp
    if blendFunction.AlphaFormat = AC_SRC_ALPHA
    then begin
      // create alpha source data
      R := Rect(nXOriginSrc, nYOriginSrc, nXOriginSrc + nWidthSrc, nYOriginSrc + nHeightSrc);
      if not GetBitmapBytes(SrcBmp, R, rileDWordBoundary, SrcBytesPtr, SrcSize) then Exit(False);

      // set info to source size
      Info.Header.biWidth := nWidthSrc;
      Info.Header.biHeight := -nHeightSrc; // top down
      Info.Header.biSizeImage := nWidthSrc * nHeightSrc * 4;

      // create temp bitmap to store orginal grayscale alpha
      TmpBmp := CreateDIBSection(hdcSrc, PBitmapInfo(@Info)^, DIB_RGB_COLORS, TmpBytesPtr, 0, 0);
      if TmpBmp = 0 then Exit(False);
      if TmpBytesPtr = nil
      then begin
        FreeMem(SrcBytesPtr);
        DeleteObject(TmpBmp);
        Exit(False);
      end;
    
      // create grayscale image from alpha
      TmpRGBA := TmpBytesPtr;
      SrcRGBA := SrcBytesPtr;
      while SrcSize > 0 do
      begin
        TmpRGBA^.Blue := SrcRGBA^.Alpha;
        TmpRGBA^.Green := SrcRGBA^.Alpha;
        TmpRGBA^.Red := SrcRGBA^.Alpha;
        TmpRGBA^.Alpha := 255;
        Inc(SrcRGBA);
        Inc(TmpRGBA);
        Dec(SrcSize, 4);
      end;

      // restore to destination size
      Info.Header.biWidth := nWidthDest;
      Info.Header.biHeight := -nHeightDest; // top down
      Info.Header.biSizeImage := nWidthDest * nHeightDest * 4;

      // create bitmap to store stretched grayscale alpha
      AlphaBmp := CreateDIBSection(hdcSrc, PBitmapInfo(@Info)^, DIB_RGB_COLORS, AlphaBytesPtr, 0, 0);
      if (AlphaBmp = 0) or (AlphaBytesPtr = nil)
      then begin
        FreeMem(SrcBytesPtr);
        DeleteObject(TmpBmp);
        DeleteObject(AlphaBmp);
        Exit(False);
      end;
      
      // stretch grayscale alpha bitmap
      DC := CreateCompatibleDC(hdcSrc);
      OldBmp := SelectObject(DC, AlphaBmp);
      TmpDC := CreateCompatibleDC(hdcSrc);
      OldTmpBmp := SelectObject(TmpDC, TmpBmp);
      StretchBlt(DC, 0, 0, nWidthDest, nHeightDest, TmpDC, 0, 0, nWidthSrc, nHeightSrc, SRCCOPY);
      SelectObject(DC, OldBmp);
      DeleteDC(DC);
      SelectObject(TmpDC, OldTmpBmp);
      DeleteDC(TmpDC);
      DeleteObject(TmpBmp);
      FreeMem(SrcBytesPtr);
      
      // as long as AlphaBmp exists, AlphaBytesPtr is valid.
      CleanupAlpha := True;
    end
    else begin
      CleanupAlpha := False;
    end;

    // create new srcbmp
    SrcBmp := CreateDIBSection(hdcSrc, PBitmapInfo(@Info)^, DIB_RGB_COLORS, SrcBytesPtr, 0, 0);
    if (SrcBmp = 0) or (SrcBytesPtr = nil)
    then begin
      DeleteObject(AlphaBmp);
      DeleteObject(SrcBmp);
      Exit(False);
    end;
    SrcSize := Info.Header.biSizeImage;
    CleanupSrc := True;
    CleanupSrcPtr := False;
    SrcPixelBytes := 4;
    SrcRowStride := nWidthDest * SrcPixelBytes;

    DC := CreateCompatibleDC(hdcSrc);
    OldBmp := SelectObject(DC, SrcBmp);
    StretchBlt(DC, 0, 0, nWidthDest, nHeightDest, hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc, SRCCOPY);
    SelectObject(DC, OldBmp);
    DeleteDC(DC);

    // adjust source size
    nWidthSrc := nWidthDest;
    nHeightSrc := nHeightDest;
    nXOriginSrc := 0;
    nYOriginSrc := 0;
  end
  else begin
    // only get source data
    SrcPixelBytes := SrcSection.dsBm.bmBitsPixel shr 3;
    if SrcSection.dsBm.bmBits <> nil
    then begin
      // source is a dibsection :)
      SrcBytesPtr := SrcSection.dsBm.bmBits;
      SrcRowStride := SrcSection.dsBm.bmWidthBytes;
      CleanupSrc := False;
      CleanupSrcPtr := False;
    end
    else begin
      R := Rect(nXOriginSrc, nYOriginSrc, nXOriginSrc + nWidthSrc, nYOriginSrc + nHeightSrc);
      if not GetBitmapBytes(SrcBmp, R, rileDWordBoundary, SrcBytesPtr, SrcSize) then Exit;
      SrcRowStride := nWidthSrc * SrcPixelBytes;
      CleanupSrc := False;
      CleanupSrcPtr := True;
      nXOriginSrc := 0;
      nYOriginSrc := 0;
    end;
    AlphaBytesPtr := nil;
    CleanupAlpha := False;
  end;

  // if a palette destination or destination isn't a section, create a temp DIB
  if (DstSection.dsBm.bmBitsPixel < 24)
  or (DstSection.dsBm.bmBits = nil)
  or (DstSection.dsBmih.biCompression <> BI_RGB)
  then begin
    // create temp dib
    DstBmp := CreateDIBSection(hdcSrc, PBitmapInfo(@Info)^, DIB_RGB_COLORS, DstBytesPtr, 0, 0);
    // copy destination
    DC := CreateCompatibleDC(hdcDest);
    OldBmp := SelectObject(DC, DstBmp);
    BitBlt(DC, 0, 0, nWidthDest, nHeightDest, hdcDest, nXOriginDest, nYOriginDest, SRCCOPY);
    SelectObject(DC, OldBmp);
    DeleteDC(DC);
    DstPixelBytes := 4;
    DstRowStride := nWidthDest * DstPixelBytes;
    CleanupDst := True;
  end
  else begin
    DstBytesPtr := DstSection.dsBm.bmBits;
    DstPixelBytes := DstSection.dsBm.bmBitsPixel shr 3;
    DstRowStride := DstSection.dsBm.bmWidthBytes;
    Inc(PByte(DstBytesPtr), nXOriginDest + nYOriginDest * DstRowStride);
    CleanupDst := False;
  end;


  // blend image

  SrcLinePtr := SrcBytesPtr;
  Inc(SrcLinePtr, nXOriginSrc + nYOriginSrc * SrcRowStride);
  DstLinePtr := DstBytesPtr;

  if blendFunction.AlphaFormat = AC_SRC_ALPHA
  then begin
    if AlphaBytesPtr <> nil
    then SrcAlpha := AlphaBytesPtr;
    
    if SCA {blendFunction.SourceConstantAlpha} = 255
    then begin
      for y := 1 to nHeightDest do
      begin
        SrcRGBA := Pointer(SrcLinePtr);
        if AlphaBytesPtr = nil
        then SrcAlpha := @SrcRGBA^.Alpha;
        DstRGBA := Pointer(DstLinePtr);
        for x := 1 to nWidthDest do
        begin
          if SrcAlpha^ <> 0
          then begin
            DstRGBA^.Red   := SrcRgba^.Red   + (DstRGBA^.Red   * (255 - SrcAlpha^)) div 255;
            DstRGBA^.Green := SrcRgba^.Green + (DstRGBA^.Green * (255 - SrcAlpha^)) div 255;
            DstRGBA^.Blue  := SrcRgba^.Blue  + (DstRGBA^.Blue  * (255 - SrcAlpha^)) div 255;
            if DstPixelBytes = 4
            then DstRGBA^.Alpha := SrcAlpha^ + (DstRGBA^.Alpha * (255 - SrcAlpha^)) div 255;
          end;
          Inc(SrcRGBA);
          Inc(SrcAlpha, 4);
          Inc(PByte(DstRGBA), DstPixelBytes);
        end;
        Inc(SrcLinePtr, SrcRowStride);
        Inc(DstLinePtr, DstRowStride);
      end;
    end
    else begin
      for y := 1 to nHeightDest do
      begin
        SrcRGBA := Pointer(SrcLinePtr);
        if AlphaBytesPtr = nil
        then SrcAlpha := @SrcRGBA^.Alpha;
        DstRGBA := Pointer(DstLinePtr);
        for x := 1 to nWidthDest do
        begin
          if SrcAlpha^ <> 0
          then begin
            DstRGBA^.Red   := (SrcRgba^.Red   * SCA) div 255 + (DstRGBA^.Red   * (255 - SrcAlpha^)) div 255;
            DstRGBA^.Green := (SrcRgba^.Green * SCA) div 255 + (DstRGBA^.Green * (255 - SrcAlpha^)) div 255;
            DstRGBA^.Blue  := (SrcRgba^.Blue  * SCA) div 255 + (DstRGBA^.Blue  * (255 - SrcAlpha^)) div 255;
            if DstPixelBytes = 4
            then DstRGBA^.Alpha := (SrcAlpha^ * SCA) div 255 + (DstRGBA^.Alpha * (255 - SrcAlpha^)) div 255;
          end;
          Inc(SrcRGBA);
          Inc(SrcAlpha, 4);
          Inc(PByte(DstRGBA), DstPixelBytes);
        end;
        Inc(SrcLinePtr, SrcRowStride);
        Inc(DstLinePtr, DstRowStride);
      end;
    end;
  end
  else begin
    for y := 1 to nHeightDest do
    begin
      SrcRGBA := Pointer(SrcLinePtr);
      if AlphaBytesPtr = nil
      then SrcAlpha := @SrcRGBA^.Alpha;
      DstRGBA := Pointer(DstLinePtr);
      for x := 1 to nWidthDest do
      begin
        DstRGBA^.Red :=   (SrcRGBA^.Red   * SCA) div 255 + (DstRGBA^.Red   * (255 - SCA)) div 255;
        DstRGBA^.Green := (SrcRGBA^.Green * SCA) div 255 + (DstRGBA^.Green * (255 - SCA)) div 255;
        DstRGBA^.Blue :=  (SrcRGBA^.Blue  * SCA) div 255 + (DstRGBA^.Blue  * (255 - SCA)) div 255;
        if (DstPixelBytes = 4) and (SrcPixelBytes = 4)
        then DstRGBA^.Alpha := (SrcAlpha^ * SCA) div 255 + (DstRGBA^.Alpha * (255 - SCA)) div 255;
        Inc(PByte(SrcRGBA), SrcPixelBytes);
        Inc(PByte(DstRGBA), DstPixelBytes);
        Inc(SrcAlpha, 4);
      end;
      Inc(SrcLinePtr, SrcRowStride);
      Inc(DstLinePtr, DstRowStride);
    end;
  end;
  
  // Replace destination if needed and do cleanup
  if CleanupDst
  then begin
    DC := CreateCompatibleDC(hdcDest);
    OldBmp := SelectObject(DC, DstBmp);
    BitBlt(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest, DC, 0, 0, SRCCOPY);
    SelectObject(DC, OldBmp);
    DeleteDC(DC);
    DeleteObject(DstBmp);
  end;
  if CleanupSrc
  then DeleteObject(SrcBmp);
  if CleanupSrcPtr
  then FreeMem(SrcBytesPtr);
  if CleanupAlpha
  then DeleteObject(AlphaBmp);
end;

procedure _SHSendBackToFocusWindow_(uMsg: UINT; wp: WPARAM; lp: LPARAM); cdecl;
begin
  {$ifdef VerboseWinCE}
  DebugLn('Calling _SHSendBackToFocusWindow_, this routine is called when the real one fails dynamic loading ');
  {$endif}
end;

var
  kerneldllhandle: THandle = 0;
  aygshelldllhandle: THandle = 0;
  p: Pointer;

initialization

  // AlphaBlend initialization
  AlphaBlend := @_AlphaBlend;
  {$ifndef win32}
  kerneldllhandle := LoadLibrary(KernelDLL);
  if kerneldllhandle <> 0 then
  begin
    p := GetProcAddress(kerneldllhandle, 'AlphaBlend');
    if p <> nil then Pointer(AlphaBlend) := p;
  end;
  {$endif}


  // SHSendBackToFocusWindow
  {$ifndef win32}
  aygshelldllhandle := LoadLibrary('aygshell');
  if aygshelldllhandle <> 0 then
  begin
    // p := GetProcAddress(aygshelldllhandle, 'SHSendBackToFocusWindow'); <<-- This code doesn't work because the function is only exported by number
    p := GetProcAddress(aygshelldllhandle, PWideChar(PtrInt(97)));
    if p <> nil then Pointer(SHSendBackToFocusWindow) := p
    else SHSendBackToFocusWindow := @_SHSendBackToFocusWindow_;
  end
  else
    SHSendBackToFocusWindow := @_SHSendBackToFocusWindow_;
  {$endif}


finalization

  // AlphaBlend finalization
  AlphaBlend := @_AlphaBlend;
  if kerneldllhandle <> 0 then FreeLibrary(kerneldllhandle);
  kerneldllhandle := 0;

  // SHSendBackToFocusWindow
  SHSendBackToFocusWindow := @_SHSendBackToFocusWindow_;
  if aygshelldllhandle <> 0 then FreeLibrary(aygshelldllhandle);
  aygshelldllhandle := 0;

end.