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__)