FlashconAxImpl.h 파일

001: /*
002:  *
003:  *  @brief    WIN32 wrapper for Macromedia’s Shockwave Flash ActiveX control
004:  *            with alpha transparency support (WIN2K or higher)
005:  *
006:  *      @author   JaeWook Choi
007:  *      @version  0.93
008:  *
009:  *  @reference
010:  *
011:  *  1. Guideline how to make Flashcon (Korean)
012:  *    ( http://www.devpia.com/Forum/BoardView.aspx?no=7144&ref=7144&page=3&forumname=vc_lec&stype= )
013:  *
014:  *  2. How to add ATL control containment support to any window in Visual C++
015:  *    ( http://support.microsoft.com/kb/192560/ )
016:  *
017:  *  3. How to add ActiveX controls to an ATL composite control programmatically in Visual C++
018:  *    ( http://support.microsoft.com/default.aspx?scid=kb;en-us;218442 )
019:  *
020:  *  4. Per Pixel Alpha Blend
021:  *    ( http://codeproject.com/gdi/pxalphablend.asp )
022:  *
023:  *  5. CreateRegionFromFile
024:  *    ( http://www.codeproject.com/gdi/coolrgn.asp )
025:  *
026:  *  @history
027:  *    0.93 (09.28.2005) – Added supports for OSs which does not have the layered window (WS_EX_LAYERED) capability such as Win98
028:  *    0.92 (09.26.2005) – Added Drag and Move support (Pressing and holding DragMove key allows user to move Flash around)
029:  *                      – Changed to use ScopeGuard instead of my own AutoMateEx class
030:  *    0.91 (09.24.2005) – Added TransparentKey setting. When it is set, user can’t close the flash nor select it with the mouse
031:  *    0.90 (09.23.2005) – Initial release
032:  *
033:  *
034:  *      <b><i>This software is provided “as is” without express or implied warranty. Use it at your own risk!</i></b>
035:  *
036:  */
037: #if !defined(__FLASHCONAXIMPL_H__INCLUDED__)
038: #define __FLASHCONAXIMPL_H__INCLUDED__
039:
040: #if _MSC_VER >= 1000
041: #pragma once
042: #endif // _MSC_VER >= 1000
043:
044: ////////////////////////////////////////////////////////////////////////////////////////////////////
045:
046: //#if _WIN32_WINNT < 0x0500
047: //#pragma message(“REMINDER : Layered Windows support requires Windows 2000 or higher.”)
048: //#endif  // #if _WIN32_WINNT < 0x0500
049:
050: ////////////////////////////////////////////////////////////////////////////////////////////////////
051:
052: #ifndef __ATLDEF_H__
053: // AtlAxWinInit is implemented in Atl.dll
054: #pragma comment(lib, “atl.lib”)
055: #pragma message(“Linking to ‘atl.lib'”)
056: #include <atldef.h>
057: #define _ATL_DLL_IMPL
058: #include <atliface.h>
059: #endif  // #ifndef __ATLDEF_H__
060:
061: // ATL projects built for MinDependency need Atl.dll if the projects use ATL control containment code in Visual C++ 6.0
062: // ( http://support.microsoft.com/kb/244955/ )
063:
064: ////////////////////////////////////////////////////////////////////////////////////////////////////
065:
066: // AlphaBlend() API
067: #pragma comment(lib, “Msimg32.lib”)
068:
069: ////////////////////////////////////////////////////////////////////////////////////////////////////
070:
071: // WIN32 instance subclassing
072: #include “MessageHook.h”
073: using mhfx::CMessageHookImplT;
074:
075: namespace mhfx
076: {
077:
078: #include “ScopeGuard.h”
079:
080: ///////////////////////////////////////////////////////////////////////////////////////////////////
081:
082: // clsid
083: static const CLSID CLSID_ShockwaveFlash = { 0xD27CDB6E, 0xAE6D, 0x11CF, { 0x96, 0xB8, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 } };
084: // clsid string
085: static LPCWSTR szCLSID_ShockwaveFlash = L”{D27CDB6E-AE6D-11cf-96B8-444553540000}”;
086:
087: ////////////////////////////////////////////////////////////////////////////////////////////////////
088:
089: #ifndef WS_EX_LAYERED
090: #define WS_EX_LAYERED           0x80000
091: #endif  // #ifndef WS_EX_LAYERED
092:
093: #ifndef ULW_ALPHA
094: #define ULW_ALPHA               0x00000002
095: #endif  // #ifndef ULW_ALPHA
096:
097: #define SHIFTED            0x8000
098:
099: ////////////////////////////////////////////////////////////////////////////////////////////////////
100:
101: using ShockwaveFlashObjects::IShockwaveFlash;
102: //
103: // error C2653: ‘ShockwaveFlashObjects’ : is not a class or namespace name
104: //
105: // #import “%SystemRoot%/system32/Macromed/Flash/Flash.ocx”
106: //
107: // , where %SystemRoot% is the window install directory
108:
109: ////////////////////////////////////////////////////////////////////////////////////////////////////
110:
111: template<class T>
112: class CFlashconAxImplT : public CMessageHookImplT<T, CFlashconAxImplT>
113: {
114:   typedef CMessageHookImplT<T, CFlashconAxImplT> baseHookClass;
115:
116:   // typedef UpdateLayeredWindow()
117:   typedef BOOL (WINAPI * lpfnUpdateLayeredWindow)(HWND, HDC, POINT *, SIZE *, HDC, POINT *, COLORREF, BLENDFUNCTION *, DWORD);
118:
119:   // data members
120: private:
121:   //
122:   lpfnUpdateLayeredWindow m_pfnUpdateLayeredWindow;
123:   //
124:   IShockwaveFlash * m_pSF;
125:   //
126:   IViewObject * m_pVO;
127:   //
128:   bool m_bUseWindowless;
129:   // 0 (transparent) ~ 100 (opaque)
130:   BYTE m_bySourceConstantAlpha;
131:   //
132:   bool m_bUseTransparentKey;
133:   //
134:   int m_vkDragMove;
135:
136:   // message map
137:   BEGIN_MSG_HOOK_MAP(CFlashconAxImplT)
138:     MESSAGE_HANDLER(WM_PAINT,     OnPaint)
139:     MESSAGE_HANDLER(WM_NCHITTEST, OnNcHitTest)
140:   END_MSG_HOOK_MAP()
141:
142:   // message handlers
143: protected:
144:   //
145:   LRESULT OnPaint(UINT uMsg, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL & /*bHandled*/)
146:   {
147:     ATLASSERT(WM_PAINT == uMsg);
148:     uMsg;
149:    
150:     PAINTSTRUCT ps = { 0 };
151:
152:     HDC hdc = ::BeginPaint(GetHwndHooked(), &ps);
153:     hdc;
154:
155:     _UpdateLayeredFlash(hdc);
156:
157:     ::EndPaint(GetHwndHooked(), &ps);
158:
159:     return 0;
160:   }
161:   //
162:   LRESULT OnNcHitTest(UINT uMsg, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL & bHandled)
163:   {
164:     ATLASSERT(WM_NCHITTEST == uMsg);
165:     uMsg;
166:
167:     const SHORT nVirtKey = ::GetKeyState(m_vkDragMove);
168:     if( SHIFTED & nVirtKey )
169:     {
170:       // to allow for user to drag and move the flash around
171:       // when m_vkDragMove key (default: SHIFT key) is pressed and hold
172:       return HTCAPTION;
173:     }
174:     else
175:     {
176:       bHandled = FALSE;
177:     }
178:
179:     return 0;
180:   }
181:
182: public:
183:   // c’tor
184:   CFlashconAxImplT()
185:     : m_pSF(NULL), m_pVO(NULL), m_pfnUpdateLayeredWindow(NULL),
186:       m_bUseWindowless(true), m_bySourceConstantAlpha(100), m_bUseTransparentKey(false), m_vkDragMove(VK_SHIFT)
187:   {
188:   }
189:   // d’tor
190:   ~CFlashconAxImplT()
191:   {
192:   }
193:
194:   // properties
195: public:
196:   // 0 (transparent) ~ 100 (opaque)
197:   inline T & SetAlpahTransparency(BYTE byAlphaTransparency)
198:   {
199:     m_bySourceConstantAlpha = (BYTE)(100 < byAlphaTransparency ? 100 : byAlphaTransparency);
200:
201:     if(::IsWindow(GetHwndHooked()))
202:     {
203:       ::InvalidateRect(GetHwndHooked(), NULL, FALSE);
204:     }
205:    
206:     return static_cast<T &>(*this);
207:   }
208:   //
209:   inline BYTE GetAlphaTransparency() const
210:   {
211:     return m_bySourceConstantAlpha;
212:   }
213:   //
214:   T & SetTransparentKey(BOOL bEnable)
215:   {
216:     // TransparentKey setting here is a bit diffrent from what it is in .NET.
217:     // It simply make the user can’t close the window, select it with the mouse
218:     // by setting WS_EX_TRANSPARENT style
219:     m_bUseTransparentKey = (FALSE != bEnable);
220:
221:     if(::IsWindow(GetHwndHooked()))
222:     {
223:       if(m_bUseTransparentKey)
224:       {
225:         const DWORD dwExStyle = ::GetWindowLong(GetHwndHooked(), GWL_EXSTYLE);
226:         ::SetWindowLong(GetHwndHooked(), GWL_EXSTYLE, dwExStyle | WS_EX_TRANSPARENT);
227:       }
228:       else
229:       {
230:         const DWORD dwExStyle = ::GetWindowLong(GetHwndHooked(), GWL_EXSTYLE);
231:         ::SetWindowLong(GetHwndHooked(), GWL_EXSTYLE, dwExStyle & ~WS_EX_TRANSPARENT);
232:       }
233:     }
234:
235:     return static_cast<T &>(*this);
236:   }
237:   //
238:   inline BOOL GetTransparentKey() const
239:   {
240:     return m_bUseTransparentKey;
241:   }
242:   // @param vkDragMove –  VK_SHIFT, VK_CONTROL, VK_MENU, VK_LSHIFT, VK_RSHIFT,
243:   //                      VK_LCONTROL, VK_RCONTROL, VK_LMENU or VK_RMENU
244:   T & SetDragMoveKey(int vkDragMove = VK_SHIFT)
245:   {
246:     m_vkDragMove = vkDragMove;
247:
248:     return static_cast<T &>(*this);
249:   }
250:   //
251:   int GetDragMoveKey() const
252:   {
253:     return m_vkDragMove;
254:   }
255:    
256:   // operations
257: public:
258:   //
259:   inline HRESULT GetControl(IShockwaveFlash ** ppFlash)
260:   {
261:     return AtlAxGetControl(GetHwndHooked(), (IUnknown **)ppFlash);
262:   }
263:   //
264:   inline HRESULT GetHost(IUnknown ** ppUnkContainer)
265:   {
266:     return AtlAxGetHost(GetHwndHooked(), ppUnkContainer);
267:   }
268:   //
269:   HRESULT CreateAxControl(HWND hwndParent, RECT & rcPos, HINSTANCE hInstance,
270:     IShockwaveFlash ** ppFlash, IUnknown ** ppUnkContainer = NULL)
271:   {
272:     if(NULL == ppFlash)
273:       return E_POINTER;
274:
275:     if(!_Init())
276:       return E_FAIL;
277:
278:     *ppFlash = NULL;
279:
280:     if(NULL != ppUnkContainer)
281:       *ppUnkContainer = NULL;
282:
283:     ////////////////////////////////////////////////////////////////////////////////////////////////////
284:
285:     const DWORD dwStyle = WS_POPUP | WS_VISIBLE;
286:     const DWORD dwExStyle =  WS_EX_TOOLWINDOW | WS_EX_TOPMOST | WS_EX_LAYERED;
287:
288:     HWND hwndCtrl = ::CreateWindowEx(dwExStyle, “AtlAxWin”, NULL,
289:       dwStyle, rcPos.left, rcPos.top, rcPos.right – rcPos.left, rcPos.bottom – rcPos.top,
290:       hwndParent, NULL, hInstance, NULL);
291:
292:     if(!::IsWindow(hwndCtrl))
293:       return E_FAIL;
294:
295:     if(!m_bUseWindowless)
296:     {
297:       HRGN hrgnNull = ::CreateRectRgn(0, 0, 0, 0);
298:       ::SetWindowRgn(hwndCtrl, hrgnNull, TRUE);
299:     }
300:
301:     ////////////////////////////////////////////////////////////////////////////////////////////////////
302:
303:     T * pT = static_cast<T *>(this);
304:     pT;
305:
306:     HRESULT hr = pT->AttachAxControl(hwndCtrl, ppFlash, ppUnkContainer);
307:
308:     return hr;
309:   }
310:
311:   // overrides
312: public:
313:   //
314:   HRESULT AttachAxControl(HWND hWnd, IShockwaveFlash ** ppFlash, IUnknown ** ppUnkContainer = NULL)
315:   {
316:     ATLASSERT(::IsWindow(hWnd));
317:
318:     if(NULL == ppFlash)
319:       return E_POINTER;
320:
321:     if(!_Init())
322:       return E_FAIL;
323:
324:     *ppFlash = NULL;
325:
326:     if(NULL != ppUnkContainer)
327:       *ppUnkContainer = NULL;
328:
329:     ////////////////////////////////////////////////////////////////////////////////////////////////////
330:
331:     if(!m_bUseWindowless)
332:     {
333:       HRGN hrgnNull = ::CreateRectRgn(0, 0, 0, 0);
334:       ::SetWindowRgn(hWnd, hrgnNull, TRUE);
335:     }
336:
337:     ////////////////////////////////////////////////////////////////////////////////////////////////////
338:
339:     HRESULT hr = S_OK;
340:
341:     // to create a Flash ActiveX control
342:     hr = ::CoCreateInstance(CLSID_ShockwaveFlash, NULL,
343:       CLSCTX_ALL, __uuidof(IShockwaveFlash), (void **)&m_pSF);
344:     if(FAILED(hr))
345:       return hr;
346:
347:     ////////////////////////////////////////////////////////////////////////////////////////////////////
348:
349:     // to store IViewObject interface for later usage
350:     hr = m_pSF->QueryInterface(__uuidof(IViewObject), (void **)&m_pVO);
351:     if(FAILED(hr) || NULL == m_pVO)
352:       return E_NOINTERFACE;
353:
354:     ////////////////////////////////////////////////////////////////////////////////////////////////////
355:
356:     // to set windowless mode (Transparent mode)
357:     hr = m_pSF->put_WMode(L”Transparent”);
358:     if(FAILED(hr))
359:       return hr;
360:
361:     if(m_bUseWindowless)
362:     {
363:       // to set WS_EX_LAYERED flag
364:       const DWORD dwExStyle = ::GetWindowLong(hWnd, GWL_EXSTYLE);
365:       ::SetWindowLong(hWnd, GWL_EXSTYLE, dwExStyle | WS_EX_LAYERED);
366:     }
367:     else
368:     {
369:       // to reset WS_EX_LAYERED flag
370:       const DWORD dwExStyle = ::GetWindowLong(hWnd, GWL_EXSTYLE);
371:       ::SetWindowLong(hWnd, GWL_EXSTYLE, dwExStyle & ~WS_EX_LAYERED);
372:     }
373:
374:     ////////////////////////////////////////////////////////////////////////////////////////////////////
375:
376:     if(m_bUseTransparentKey)
377:     {
378:       const DWORD dwExStyle = ::GetWindowLong(hWnd, GWL_EXSTYLE);
379:       ::SetWindowLong(hWnd, GWL_EXSTYLE, dwExStyle | WS_EX_TRANSPARENT);
380:     }
381:     else
382:     {
383:       const DWORD dwExStyle = ::GetWindowLong(hWnd, GWL_EXSTYLE);
384:       ::SetWindowLong(hWnd, GWL_EXSTYLE, dwExStyle & ~WS_EX_TRANSPARENT);
385:     }
386:
387:     ////////////////////////////////////////////////////////////////////////////////////////////////////
388:
389:     IUnknown * pUnkContainer = NULL;
390:         hr = AtlAxAttachControl(m_pSF, hWnd, &pUnkContainer);
391:     if(FAILED(hr))
392:       return hr;
393:    
394:     ////////////////////////////////////////////////////////////////////////////////////////////////////
395:
396:     // to receive WM_PAINT message
397:     if(!Hook(hWnd))
398:     {
399:       pUnkContainer->Release();
400:       pUnkContainer = NULL;
401:
402:       return E_FAIL;
403:     }
404:
405:     ////////////////////////////////////////////////////////////////////////////////////////////////////
406:
407:     *ppFlash = m_pSF;
408:     static_cast<IUnknown *>(*ppFlash)->AddRef();
409:
410:     if(NULL != ppUnkContainer)
411:     {
412:       *ppUnkContainer = pUnkContainer;
413:       static_cast<IUnknown *>(*ppUnkContainer)->AddRef();
414:     }
415:
416:     pUnkContainer->Release();
417:     pUnkContainer = NULL;
418:
419:     ////////////////////////////////////////////////////////////////////////////////////////////////////
420:
421:     return hr;
422:   }
423:   //
424:   void OnPreFinalMessage(HWND /*hWnd*/)
425:   {
426:     _Term();
427:   }
428:
429:    // Implementations
430: protected:
431:   //
432:   BOOL _Init()
433:   {
434:     // to initialize ATL control containment code.
435:     if(!AtlAxWinInit())
436:       return FALSE;
437:
438:     if(NULL == m_pfnUpdateLayeredWindow)
439:     {
440:       // to import functions from USER32.DLL
441:       HMODULE hUser32DLL = ::GetModuleHandle(_T(“USER32.DLL”));
442:       if(hUser32DLL)
443:       {
444:         m_pfnUpdateLayeredWindow =
445:           (lpfnUpdateLayeredWindow)::GetProcAddress(hUser32DLL, “UpdateLayeredWindow”);
446:         if(m_pfnUpdateLayeredWindow)
447:           return TRUE;
448:       }
449:
450:       // UpdateLayredWindow() is not avialbe
451:       // therefore we use the traditional SetWindowRgn() technique instead
452:       m_bUseWindowless = false;
453:     }
454:
455:     return TRUE;
456:   }
457:   //
458:   void _Term()
459:   {
460:     if(m_pVO)
461:     {
462:       m_pVO->Release();
463:       m_pVO = NULL;
464:     }
465:
466:     if(m_pSF)
467:     {
468:       m_pSF->Release();
469:       m_pSF = NULL;
470:     }
471:   }
472:   //
473:   BOOL _UpdateLayeredFlash(HDC hdc = NULL)
474:   {
475:     if(NULL == m_pSF || NULL == m_pVO)
476:       return FALSE;
477:
478:     RECT rcWindow = { 0 };
479:     ::GetWindowRect(GetHwndHooked(), &rcWindow);
480:     if(!m_bUseWindowless)
481:       ::MapWindowPoints(NULL, GetHwndHooked(), (LPPOINT)&rcWindow, 2);
482:
483:     ////////////////////////////////////////////////////////////////////////////////////////////////////
484:
485:     HDC hdcScreen = m_bUseWindowless ? ::GetDC(NULL) : hdc;
486:     ScopeGuard sg_ReleaseDC = MakeGuard(ReleaseDC, (HWND)NULL, hdcScreen);
487:     if(!m_bUseWindowless)
488:       sg_ReleaseDC.Dismiss();
489:
490:     HDC hdcMemory = ::CreateCompatibleDC(hdcScreen);
491:     ON_BLOCK_EXIT(&::DeleteDC, hdcMemory);
492:
493:     ////////////////////////////////////////////////////////////////////////////////////////////////////
494:
495:     // to create RGBBitmap
496:     BITMAPINFO bmi = { 0 };
497:     bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
498:     bmi.bmiHeader.biPlanes = 1;
499:     bmi.bmiHeader.biBitCount = 32;
500:     bmi.bmiHeader.biCompression = BI_RGB;
501:     bmi.bmiHeader.biWidth = rcWindow.right – rcWindow.left;
502:     bmi.bmiHeader.biHeight = rcWindow.bottom – rcWindow.top;
503:
504:     LPBYTE pbmpBits = NULL;
505:     HBITMAP hbmp = ::CreateDIBSection(hdcScreen, (LPBITMAPINFO)&bmi, DIB_RGB_COLORS, (void **)&pbmpBits, NULL, 0);
506:     if(NULL == hbmp)
507:       return FALSE;
508:     ON_BLOCK_EXIT(&::DeleteObject, hbmp);
509:
510:     ////////////////////////////////////////////////////////////////////////////////////////////////////
511:
512:     HBITMAP hbmpOld = (HBITMAP)::SelectObject(hdcMemory, hbmp);
513:     ON_BLOCK_EXIT(&::SelectObject, hdcMemory, hbmpOld);
514:
515:     ////////////////////////////////////////////////////////////////////////////////////////////////////
516:
517:     HRESULT hr = S_OK;
518:     hr = m_pVO->Draw(DVASPECT_CONTENT, -1, NULL, NULL, NULL, hdcMemory, (RECTL *)0, (RECTL *)0, NULL, NULL);
519:     if(FAILED(hr))
520:       return FALSE;
521:
522:     BITMAP bm = { 0 };
523:     if(::GetObject(hbmp, sizeof(BITMAP), &bm) != sizeof(BITMAP))
524:       return FALSE;
525:
526:     SIZE szBmp = { bm.bmWidth, bm.bmHeight };
527:
528:     if(m_bUseWindowless)
529:     {
530:       POINT ptDest = { rcWindow.left, rcWindow.top }, ptSrc = { 0 };
531:     
532:       BLENDFUNCTION bf = { AC_SRC_OVER, 0, (BYTE)(255 * m_bySourceConstantAlpha / 100), AC_SRC_ALPHA };
533:       if(!m_pfnUpdateLayeredWindow(GetHwndHooked(), hdcScreen, &ptDest, &szBmp, hdcMemory, &ptSrc, 0, &bf, ULW_ALPHA))
534:         return FALSE;
535:     }
536:     else
537:     {
538:       //
539:       // to contour out the transparent area using the boundary detection and SetWindowRgn() API
540:       //
541:       // Threre are two flaws found in the following cases
542:       //
543:       // 1) Some ghost image can be seen in the translucent portion of the bitmap image
544:       //    a) when the translucent portion is getting overrlapped by some animated image, or
545:       //    b) when it is being dragged and moved
546:       //
547:       // 2) It does not display image when the region is very complex
548:       //    (Why? CreateRgnFromFile() does not return the correct region in such case)
549:       //
550:
551:       HRGN hRgn = CreateRgnFromFile(hbmp, RGB(0,0,0));
552:
553: #ifdef _DEBUG
554:
555:       const DWORD dwCount = ::GetRegionData(hRgn, 0, NULL);
556:
557:       LPRGNDATA lpRgnData = (LPRGNDATA)new byte[dwCount];
558:       ::GetRegionData(hRgn, dwCount, lpRgnData);
559:
560:       lpRgnData->rdh;
561:
562:       delete [] lpRgnData;
563:
564: #endif
565:      
566:       if(hRgn)
567:         ::SetWindowRgn(GetHwndHooked(), hRgn, TRUE);
568:
569:       BLENDFUNCTION bf = { AC_SRC_OVER, 0, (BYTE)(255 * m_bySourceConstantAlpha / 100), AC_SRC_ALPHA };
570:       ::AlphaBlend(hdcScreen, 0, 0, szBmp.cx, szBmp.cy, hdcMemory, 0, 0, szBmp.cx, szBmp.cy, bf);
571:     }
572:
573:     ////////////////////////////////////////////////////////////////////////////////////////////////////
574:
575:     return TRUE;
576:
577:     ON_BLOCK_END
578:     ON_BLOCK_END
579:     ON_BLOCK_END
580:   }
581:
582:   // @brief create HRGN from the specified BITMAP
583:   //
584:   // @param hBmp – [in] the input bitmap from wihch the region is created
585:   // @param color – [in] the transparent color key
586:   //
587:   // Excerpt from CreateRegionFromFile ( http://www.codeproject.com/gdi/coolrgn.asp )
588:   //
589:   HRGN CreateRgnFromFile( HBITMAP hBmp, COLORREF color)
590:   {
591:     // get image properties
592:     BITMAP bmp = { 0 };
593:     ::GetObject( hBmp, sizeof(BITMAP), &bmp );
594:     // allocate memory for extended image information
595:     LPBITMAPINFO bi = (LPBITMAPINFO) new BYTE[ sizeof(BITMAPINFO) + 2 * sizeof(RGBQUAD) ];
596:     ::memset( bi, 0, sizeof(BITMAPINFO) + 8 );
597:     bi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
598:     // set window size
599:     //    szBmp.cx = bmp.bmWidth;    // bitmap width
600:     //    szBmp.cy  = bmp.bmHeight;   // bitmap height
601:     // create temporary dc
602:     HDC dc = ::CreateIC(_T(“DISPLAY”),NULL,NULL,NULL );
603:     // get extended information about image (length, compression, length of color table if exist, …)
604:     DWORD res = ::GetDIBits( dc, hBmp, 0, bmp.bmHeight, 0, bi, DIB_RGB_COLORS );
605:     // allocate memory for image data (colors)
606:     LPBYTE pBits = new BYTE[ bi->bmiHeader.biSizeImage + 2 ];
607:     // allocate memory for color table
608:     if ( bi->bmiHeader.biBitCount == 8 )
609:     {
610:       // actually color table should be appended to this header(BITMAPINFO),
611:       // so we have to reallocate and copy it
612:       LPBITMAPINFO old_bi = bi;
613:       // 255 – because there is one in BITMAPINFOHEADER
614:       bi = (LPBITMAPINFO)new char[ sizeof(BITMAPINFO) + 255 * sizeof(RGBQUAD) ];
615:       ::memcpy( bi, old_bi, sizeof(BITMAPINFO) );
616:       // release old header
617:       delete old_bi;
618:     }
619:     // get bitmap info header
620:     BITMAPINFOHEADER& bih = bi->bmiHeader;
621:     // get color table (for 256 color mode contains 256 entries of RGBQUAD(=DWORD))
622:     LPDWORD clr_tbl = (LPDWORD)&bi->bmiColors;
623:     // fill bits buffer
624:     res = ::GetDIBits( dc, hBmp, 0, bih.biHeight, pBits, bi, DIB_RGB_COLORS );
625:     ::DeleteDC( dc );
626:    
627:     BITMAP bm;
628:     ::GetObject( hBmp, sizeof(BITMAP), &bm );
629:     // shift bits and byte per pixel (for comparing colors)
630:     LPBYTE pClr = (LPBYTE)&color;
631:     // swap red and blue components
632:     BYTE tmp = pClr[0]; pClr[0] = pClr[2]; pClr[2] = tmp;
633:     // convert color if curent DC is 16-bit (5:6:5) or 15-bit (5:5:5)
634:     if ( bih.biBitCount == 16 )
635:     {
636:       // for 16 bit
637:       color = ((DWORD)(pClr[0] & 0xf8) >> 3) |
638:         ((DWORD)(pClr[1] & 0xfc) << 3) |
639:         ((DWORD)(pClr[2] & 0xf8) << 8);
640:       // for 15 bit
641:       //    color = ((DWORD)(pClr[0] & 0xf8) >> 3) |
642:       //        ((DWORD)(pClr[1] & 0xf8) << 2) |
643:       //        ((DWORD)(pClr[2] & 0xf8) << 7);
644:     }
645:    
646:     const DWORD RGNDATAHEADER_SIZE  = sizeof(RGNDATAHEADER);
647:     const DWORD ADD_RECTS_COUNT   = 40;     // number of rects to be appended
648:     // to region data buffer
649:    
650:     // BitPerPixel
651:     BYTE  Bpp = (BYTE)(bih.biBitCount >> 3);        // bytes per pixel
652:     // bytes per line in pBits is DWORD aligned and bmp.bmWidthBytes is WORD aligned
653:     // so, both of them not
654:     DWORD m_dwAlignedWidthBytes = (bmp.bmWidthBytes & ~0x3) + (!!(bmp.bmWidthBytes & 0x3) << 2);
655:     // DIB image is flipped that’s why we scan it from the last line
656:     LPBYTE  pColor = pBits + (bih.biHeight – 1) * m_dwAlignedWidthBytes;
657:     DWORD dwLineBackLen = m_dwAlignedWidthBytes + bih.biWidth * Bpp;  // offset of previous scan line
658:     // (after processing of current)
659:     DWORD dwRectsCount = bih.biHeight;      // number of rects in allocated buffer
660:     INT   i, j;                 // current position in mask image
661:     INT   first = 0;                // left position of current scan line
662:     // where mask was found
663:     bool  wasfirst = false;           // set when mask has been found in current scan line
664:     bool  ismask = false;                 // set when current color is mask color
665:    
666:     // allocate memory for region data
667:     // region data here is set of regions that are rectangles with height 1 pixel (scan line)
668:     // that’s why first allocation is <bm.biHeight> RECTs – number of scan lines in image
669:     RGNDATAHEADER* pRgnData =
670:       (RGNDATAHEADER*)new BYTE[ RGNDATAHEADER_SIZE + dwRectsCount * sizeof(RECT) ];
671:     // get pointer to RECT table
672:     LPRECT pRects = (LPRECT)((LPBYTE)pRgnData + RGNDATAHEADER_SIZE);
673:     // zero region data header memory (header  part only)
674:     ::memset( pRgnData, 0, RGNDATAHEADER_SIZE + dwRectsCount * sizeof(RECT) );
675:     // fill it by default
676:     pRgnData->dwSize  = RGNDATAHEADER_SIZE;
677:     pRgnData->iType   = RDH_RECTANGLES;
678:    
679:     for ( i = 0; i < bih.biHeight; i++ )
680:     {
681:       for ( j = 0; j < bih.biWidth; j++ )
682:       {
683:         // get color
684:         switch ( bih.biBitCount )
685:         {
686:         case 8:
687:           ismask = (clr_tbl[ *pColor ] != color);
688:           break;
689:         case 16:
690:           ismask = (*(LPWORD)pColor != (WORD)color);
691:           break;
692:         case 24:
693:           ismask = ((*(LPDWORD)pColor & 0x00ffffff) != color);
694:           break;
695:         case 32:
696:           ismask = (*(LPDWORD)pColor != color);
697:         }
698:         // shift pointer to next color
699:         pColor += Bpp;
700:         // place part of scan line as RECT region if transparent color found after mask color or
701:         // mask color found at the end of mask image
702:         if ( wasfirst )
703:         {
704:           if ( !ismask )
705:           {
706:             // save current RECT
707:             const RECT rcTemp = { first, i, j, i + 1 };
708:             pRects[ pRgnData->nCount++ ] = rcTemp;
709:             // if buffer full reallocate it with more room
710:             if ( pRgnData->nCount >= dwRectsCount )
711:             {
712:               dwRectsCount += ADD_RECTS_COUNT;
713:               // allocate new buffer
714:               LPBYTE pRgnDataNew = new BYTE[ RGNDATAHEADER_SIZE + dwRectsCount * sizeof(RECT) ];
715:               // copy current region data to it
716:               ::memcpy( pRgnDataNew, pRgnData, RGNDATAHEADER_SIZE + pRgnData->nCount * sizeof(RECT) );
717:               // delte old region data buffer
718:               delete pRgnData;
719:               // set pointer to new regiondata buffer to current
720:               pRgnData = (RGNDATAHEADER*)pRgnDataNew;
721:               // correct pointer to RECT table
722:               pRects = (LPRECT)((LPBYTE)pRgnData + RGNDATAHEADER_SIZE);
723:             }
724:             wasfirst = false;
725:           }
726:         }
727:         else if ( ismask )    // set wasfirst when mask is found
728:         {
729:           first = j;
730:           wasfirst = true;
731:         }
732:       }
733:      
734:       if ( wasfirst && ismask )
735:       {
736:         // save current RECT
737:         const RECT rcTemp = { first, i, j, i + 1 };
738:         pRects[ pRgnData->nCount++ ] = rcTemp;
739:         // if buffer full reallocate it with more room
740:         if ( pRgnData->nCount >= dwRectsCount )
741:         {
742:           dwRectsCount += ADD_RECTS_COUNT;
743:           // allocate new buffer
744:           LPBYTE pRgnDataNew = new BYTE[ RGNDATAHEADER_SIZE + dwRectsCount * sizeof(RECT) ];
745:           // copy current region data to it
746:           ::memcpy( pRgnDataNew, pRgnData, RGNDATAHEADER_SIZE + pRgnData->nCount * sizeof(RECT) );
747:           // delte old region data buffer
748:           delete pRgnData;
749:           // set pointer to new regiondata buffer to current
750:           pRgnData = (RGNDATAHEADER*)pRgnDataNew;
751:           // correct pointer to RECT table
752:           pRects = (LPRECT)((LPBYTE)pRgnData + RGNDATAHEADER_SIZE);
753:         }
754:         wasfirst = false;
755:       }
756:      
757:       pColor -= dwLineBackLen;
758:     }
759:     // release image data
760:     delete pBits;
761:     delete bi;
762:    
763:     // create region
764:     HRGN hRgn = ::ExtCreateRegion( NULL, RGNDATAHEADER_SIZE + pRgnData->nCount * sizeof(RECT), (LPRGNDATA)pRgnData );
765:     // release region data
766:     delete pRgnData;
767:    
768:     return hRgn;
769:   }
770:
771: };  // template<class T> class CFlashconAxImplT : public CMessageHookImplT<T, CFlashconAxImplT>
772:
773: } // namespace mhfx
774:
775: ////////////////////////////////////////////////////////////////////////////////////////////////////
776: //
777: // Property ID for TGetProperty() and TSetProperty()
778: //
779: // @example
780: //
781: // strName = TGetProperty(“/”, FPID_URL); // to retrieve the Flash’s URL
782: //
783: // TSetProperty(“/”, FPID_VISIBILITY, “0”); // to hide the flash
784: //
785: // @reference
786: //
787: // Embedding Movies with Flash, Part I: Basic Methods
788: // ( http://www.webreference.com/js/column85/ )
789: //
790: // Embedding Movies with Flash, Part II: Basic Properties
791: // ( http://www.webreference.com/js/column86/ )
792: //
793: // Embedding Movies with Flash, Part III: More Properties
794: // ( http://www.webreference.com/js/column87/ )
795: //
796: #define FPID_X_POSITION      0
797: #define FPID_Y_POSITION      1
798: #define FPID_X_SCALE         2
799: #define FPID_Y_SCALE         3
800: #define FPID_CURRENT_FRAME   4
801: #define FPID_TOTAL_FRAME     5
802: #define FPID_ALPHA           6
803: #define FPID_VISIBILITY      7
804: #define FPID_WIDTH           8
805: #define FPID_HEIGHT          9
806: #define FPID_ROTATION        10
807: #define FPID_FRAMELOADED     12
808: #define FPID_NAME            13
809: #define FPID_URL             15
810: #define FPID_HIGHQUALITY     16
811:
812: #endif  // #if !defined(__FLASHCONAXIMPL_H__INCLUDED__)

Leave a Reply

Your email address will not be published. Required fields are marked *