flash 궁금하니?

네이트온 처럼 플래시콘 만들기

deguls 2008. 8. 4. 16:00
출처: http://flashcafe.org/bbs/board.php?bo_table=programming_study&wr_id=46&page=10&page=10


 신형철님의 "네이트온 처럼 플래시콘 만들기" 강좌를 바탕으로하여 만들었습니다.
  글쓴이 : 손님     날짜 : 05-11-09 18:25     조회 : 1495    
  http://cafe.naver.com/q69/8429 (246)

신형철님의 "네이트온 처럼 플래시콘 만들기" 강좌를 바탕으로하여 만들었습니다.

(  http://www.devpia.com/Forum/BoardView.aspx?no=7144&ref=7144&page=3&forumname=vc_lec&stype=  )



MFC/ATL/WTL/WIN32 환경에서 사용할 수 있지만 Layered Windows 지원 때문에 Win2000 이상에서만 windowless 모드로 투명하게 작동합니다. ( Win98 등등의 환경에서는 그냥 window 모드로 작동합니다. (작동할 겁니다.) )






예제프로젝트


MFC 예제 프로젝트입니다. 플래시 파일을 다이알로그에 드래그앤드랍 해주면 스크린 좌표 (50, 50) 에 가로 350, 세로 250의 크기로 드랍된 플래시 애니메이션을 windowless 모드로 재생합니다. 예제압축파일에 swift3d.swf, opener.swf 라는 플래시 파일을 포함했습니다. 이 파일은 http://www.webreference.com/js/column85/ 에서 다운로드 받은 파일입니다. 다이알로그에 있는 "==33" 버튼을 누르면 플래시 재생 위치를 이동시키면서 alpha transparency 값을 50% 바꿔줌으로써 플래시가 반투명 상태로 재생합니다.



멤버함수


CFlashconAxWindow & SetAlpahTransparency(BYTE byAlphaTransparency);


플래시의 알파 투명도값을 설정합니다. 0 을 설정하면 완전히 투명하게 100 (또는 그 이상)을 설정하면 완전 불투명하게 플래시를 출력합니다.


BYTE GetAlphaTransparency() const;


- 현재 설정된 알파 투명도값을 돌려줍니다. (0 ~ 100)


CFlashconAxWindow & SetTransparentKey(BOOL bEnable);


- TransparentKey를 설정합니다. 설정 후 에는 플래시 윈도를 마우스로 선택할 수 없습니다. 모든 마우스 메세지는 플래시 윈도 (또는 플래시 컨테이너 윈도가 아닌 백그라운드에 있는 윈도가 받게됩니다.  (내부적으로 WS_EX_TRANSPARENT 스타일을 적용함으로써 동작합니다.)


HRESULT GetControl(IShockwaveFlash ** ppFlash);

 

    ppFlash - [out] Flash ActivieX 컨트롤의 IShockwaveFlash 인터페이스 포인터


- 윈도 컨트롤로 부터 Flash ActiveX 컨트롤의 IShockwaveFalsh 인터페이스 포인터를 얻습니다. FSCommand 등등의 이벤트를 받고자 하는 경우에는 IShockwaveFlash 인터페이스 포인터를 사용하면 됩니다. (IConnectionPoint)


HRESULT GetHost(IUnknown ** ppUnkContainer);

 

    ppUnkContianer - [out] Flash ActiveX 컨트롤을 호스팅하는 컨테이너의 IUnknown 인터페이스 포인터


- 윈도 컨트롤로부터 Flash ActiveX 컨트롤을 호스팅하는 컨테이너의 IUnknown 인터페이스 포인터를 얻습니다.


HRESULT CreateAxControl(HWND hwndParent, RECT & rcPos, HINSTANCE hInstance, IShockwaveFlash ** ppFlash, IUnknown ** ppUnkContainer = NULL);

 

    hwndParent - [in] Flash ActivieX 컨트롤을 호스팅하기 위해 생성되는 윈도의 부모 윈도의 핸들

    rcPos - [in] 새로 생성될 윈도의 위치 및 크기 (스크린 좌표계)

    hInstance - [in] 프로그램 모듈 인스탄스 핸들

    ppFlash - [out] 생성된 Flash ActivieX 컨트롤의 IShockwaveFlash 인터페이스 포인터

    ppUnkContianer - [out] 생성된 Flash ActiveX 컨트롤을 호스팅하는 컨테이너의 IUnknown 인터페이스 포인터


- "AtlAxWin" 클래스의 윈도를 동적으로 생성하고 Flash ActiveX 컨트롤을 생성하여 이 Flash 컨트롤을 생성한 윈도에 접속시킨 후(서브클래싱)에 IShockwaveFlash 인터페이스 포인터와 Flash ActiveX를 호스팅하는 컨테이너의 IUnknown 인터페이스 포인터를 돌려줍니다.


HRESULT AttachAxControl(HWND hWnd, IShockwaveFlash ** ppFlash, IUnknown ** ppUnkContainer = NULL);

 

    hWnd - [in] Flash ActivieX 컨트롤을 호스팅할 윈도

    ppFlash - [out] 생성된 Flash ActivieX 컨트롤의 IShockwaveFlash 인터페이스 포인터

    ppUnkContianer - [out] 생성된 Flash ActiveX 컨트롤을 호스팅하는 컨테이너의 IUnknown 인터페이스 포인터


- Flash ActiveX 컨트롤을 생성한 후 입력으로 주어진 이미 생성된 윈도에 접속시킨 후(서브클래싱)에 IShockwaveFlash 인터페이스 포인터와 Flash ActivX를 호스팅하는 컨테이너의 IUnknown 인터페이스 포인터를 돌려줍니다.



사용법


1. stdafx.h 파일에 다음 두줄을 추가합니다.


#import "c:/windows/system32/macromed/Flash/Flash.ocx"

using ShockwaveFlashObjects::IShockwaveFlash;


( #import 한 후 컴파일 하면 flash.tlh 파일과 flash.tli 파일이 생성됩니다. 이 두 파일에 IShockwaveFlash 등등의 인터페이스 정의가 들어있습니다. )



2. Flashcon 을 사용하고자 하는 곳에 다음과 같이 헤더파일을 인클루드 합니다.


a) MFC


#include "FlashconAxWindow.h"


b) ATL/WTL


#include "FlashconAxWindow_WTL.h"


3. 멤버 함수를 추가합니다.


CFlashconAxWindow m_wndFlash;


4-1. OnInitDialog() 등의 초기화 루틴에서 Flashcon 을 동적으로 생성하거나


a) MFC


IShockwaveFlash * pFlash = NULL;

HRESULT hr = m_wndFlash.CreateAxControl(NULL, rc, &pFlash);

ASSERT(SUCCEEDED(hr));

 

// pFlash를 사용하여 플래시 제어

 

pFlash->Release();

pFlash = NULL;

   

b) ATL/WTL


CComPtr<IShockwaveFlash> spFlash;

HRESULT hr = m_wndFlash.CreateAxControl(NULL, rc, &spFlash);

ATLASSERT(SUCCEEDED(hr));


// spFlash를 사용하여 플래시 제어


4-2. 이미 생성한 윈도를 서브클래싱을 통해서 Flashcon 윈도로 변경합니다.


a) MFC


ASSERT(::IsWindow(hwndTemp));


IShockwaveFlash * pFlash = NULL;

HRESULT hr = m_wndFlash.AttachAxControl(hwndTemp, &pFlash);

ASSERT(SUCCEEDED(hr));

 

// pFlash를 사용하여 플래시 제어

 

pFlash->Release();

pFlash = NULL;


b) ATL/WTL


ATLASSERT(::IsWindow(hwndTemp));


CComPtr<IShockwaveFlash> spFlash;

HRESULT hr = m_wndFlash.AttachAxControl(hwndTemp, &spFlash);

ATLASSERT(SUCCEEDED(hr));


// spFlash를 사용하여 플래시 제어


5. 이미 생성된 CFlashconAxWindow 로 부터 IShockwaveFlash 인터페이스 포인터를 구하고 싶은 경우에는


a) MFC


IShockwaveFlash * pFlash = NULL;

HRESULT hr = m_wndFlash.GetControl(&pFlash);


// pFlash를 사용하여 플래시 제어

 

pFlash->Release();

pFlash = NULL;

   

b) ATL/WTL


CComPtr<IShockwaveFlash> spFlash;

HRESULT hr = m_wndFlash.GetControl(&spFlash);

ATLASSERT(SUCCEEDED(hr));


// spFlash를 사용하여 플래시 제어


6. 이미 생성된 CFlashconAxWindow 의 (Flash ActiveX 컨트롤을 호스팅하는) 컨테이너의 IUnknown 인터페이스 포인터를 구하고 싶은 경우에는


a) MFC


IUnknown * pUnkContainer = NULL;

HRESULT hr = m_wndFlash.GetHost(&pUnkContainer);


// pUnkContainer를 사용하여 컨테이너 제어

 

pUnkContainer->Release();

pUnkContainer = NULL;


b) ATL/WTL


CComPtr<IUnknown> spUnkContainer;

HRESULT hr = m_wndFlash.GetHost(&spUnkContainer);


// spUnkContainer를 사용하여 컨테이너 제어


7. Flashcon 의 스크린 좌표를 변경하거나 FlashCon 의 크기를 변경하고 싶은 경우


CFlashconAxWindow 의 윈도 관리 함수(SetWindowPos, MoveWindow 등등)를 사용합니다.


ex) (100, 100) 에 가로 200, 세로 300 크기로 변경 (*** 여기서 좌표는 항상 스크린 좌표입니다. ***)

m_wndFlash.SetWindowPos(NULL, 100, 100, 200, 300, SWP_NOZORDER);



구현노트


실재 구현은 FlashconAxImpl.h 있습니다. FlashconAxImpl.h 는 WIN32 호환 코드 입니다. 즉 MFC나 ATL/WTL 등등의 플랫폼에 종속되지 않습니다. (ATL.dll 을 사용해야하고 2개의 ATL 헤더파일을 사용하긴 하지만 이 파일들은 ATL 없이도 독립적으로 동작할 수 있있는 파일이라는 관점에서 ATL에 완전히 종속되지 않는다는 의미입니다.)  FlashconAxWindow.h 와 FlashconAxWindow.cpp은 MFC 용 FlashconAxImpl.h를 사용하는 MFC를 위한 어댑터 클래스이고 FlashconAxWindow_WTL.h 는 ATL/WTL을 위한 어댑터 클래스 입니다.


신형철님의 강좌에 따라 작성하였는데 아주 조금 변경을 하였습니다. windowless 모드 플래시로 부터 컨테이너로 발생되는 WM_PAINT를 받기 위해서 서브클래싱 순서가 중요한데 이 순서를 잘못 설정해서 처음에는 TIMER를 사용했었다가 나중에서야 제대로 수정했습니다.


ATL.DLL 서비스를 사용하기 때문에 배포 시 반드시 ATL.DLL 을 같이 배포해야합니다만 ATL에 종속되지는 않습니다. 즉 ActiveX 컨트롤 호스팅하기 위해서 사용하는 ATL.dll 파일이 system32 폴더에 있어야 하며  atldef.h, atliface.h 파일을 참조할 수 있어야 컴파일이 가능합니다. VC 설치하면서 ATL 설치했으면 별 문제 없을겁니다 (참고) How to add ATL control containment support to any window in Visual C++ ( http://support.microsoft.com/kb/192560/ ) ).

ATL.dll 에 포함되어 있는 AxWindow는 ActiveX 컨트롤 호스팅을 지원해줍니다. (OCX96 specificatio, windowless activation, flicker-free drawing)


Flash ActiveX를 호스팅하는 AtlAxWin 윈도(CFlashconAxWindow)는 컨테이너의 역할 외에 Flash 컨트롤의 스크린 상에서의 Place Holder 역할을 합니다. 즉 윈도 메니징 API 함수들을 이용하여 AtlAxWin 윈도를 이동/리사이징/보이기/숨기기 등등을 수행할 수 있습니다. 추가적인 메세지 핸들링이 필요하면 CFlashconAxWindow 함수를 상속하여 메세지 핸들러를 추가해주면 됩니다.



소스코드


a) 프로젝트에 공통으로 포함해야 하는 파일

AutoMate.h

MessageHook.h

FlashconAxImpl.h


b) MFC 프로젝트에 추가로 포함해야 하는 파일

FlashconAxWindow.h

FlashconAxWindow.cpp


c) ATL/WTL 프로젝트에 추가로 포함해야 하는 파일

FlashconAxWindow_WTL.h



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.91
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:  *  @history
024:  *    0.91 (09.24.2005) - Added TransparentKey setting. When it is set, user can't close the flash nor select it with the mouse
025:  *    0.90 (09.23.2005) - Initial release
026:  *
027:  *
028:  *      <b><i>This software is provided "as is" without express or implied warranty. Use it at your own risk!</i></b>
029:  *
030:  */
031: #if !defined(__FLASHCONAXIMPL_H__INCLUDED__)
032: #define __FLASHCONAXIMPL_H__INCLUDED__
033: 
034: #if _MSC_VER >= 1000
035: #pragma once
036: #endif // _MSC_VER >= 1000
037: 
038: ////////////////////////////////////////////////////////////////////////////////////////////////////
039: 
040: #if _WIN32_WINNT < 0x0500
041: #pragma message("WARNING: Layered Windows support requires Windows 2000 or higher.")
042: #endif  // #if _WIN32_WINNT < 0x0500
043: 
044: ////////////////////////////////////////////////////////////////////////////////////////////////////
045: 
046: #ifndef __ATLDEF_H__
047: // AtlAxWinInit is implemented in Atl.dll
048: #pragma comment(lib, "atl.lib")
049: #include <atldef.h>
050: #define _ATL_DLL_IMPL
051: #include <atliface.h>
052: #endif  // #ifndef __ATLDEF_H__
053: 
054: ////////////////////////////////////////////////////////////////////////////////////////////////////
055: 
056: // WIN32 instance subclassing
057: #include "MessageHook.h"
058: using mhfx::CMessageHookImplT;
059: 
060: // C++ RAII idiom
061: #include "AutoMateEx.h"
062: 
063: namespace mhfx
064: {
065: 
066: ////////////////////////////////////////////////////////////////////////////////////////////////////
067: 
068: // clsid
069: static const CLSID CLSID_ShockwaveFlash = { 0xD27CDB6E, 0xAE6D, 0x11CF, { 0x96, 0xB8, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 } };
070: // clsid string
071: static LPCWSTR szCLSID_ShockwaveFlash = L"{D27CDB6E-AE6D-11cf-96B8-444553540000}";
072: 
073: ////////////////////////////////////////////////////////////////////////////////////////////////////
074: 
075: #ifndef WS_EX_LAYERED
076: #define WS_EX_LAYERED           0x80000 
077: #endif  // #ifndef WS_EX_LAYERED
078: 
079: #ifndef ULW_ALPHA
080: #define ULW_ALPHA               0x00000002
081: #endif  // #ifndef ULW_ALPHA
082: 
083: ////////////////////////////////////////////////////////////////////////////////////////////////////
084: 
085: using ShockwaveFlashObjects::IShockwaveFlash;
086: //
087: // error C2653: 'ShockwaveFlashObjects' : is not a class or namespace name
088: //
089: // #import "%SystemRoot%/system32/Macromed/Flash/Flash.ocx"
090: //
091: // , where %SystemRoot% is the window install directory
092: 
093: ////////////////////////////////////////////////////////////////////////////////////////////////////
094: 
095: template<class T>
096: class CFlashconAxImplT : public CMessageHookImplT<T, CFlashconAxImplT>
097: {
098:   typedef CMessageHookImplT<T, CFlashconAxImplT> baseHookClass;
099: 
100:   // typedef UpdateLayeredWindow()
101:   typedef BOOL (WINAPI * lpfnUpdateLayeredWindow)(HWND, HDC, POINT *, SIZE *, HDC, POINT *, COLORREF, BLENDFUNCTION *, DWORD);
102: 
103:   // data members
104:   //
105:   lpfnUpdateLayeredWindow m_pUpdateLayeredWindow;
106:   //
107:   IShockwaveFlash * m_pSF;
108:   //
109:   IViewObject * m_pVO;
110:   //
111:   bool m_bUseWindowless;
112:   // 0 (transparent) ~ 100 (opaque)
113:   BYTE m_bySourceConstantAlpha;
114:   //
115:   bool m_bUseTransparentKey;
116: 
117:   // message map
118: 
119:   BEGIN_MSG_HOOK_MAP(CFlashconAxImplT)
120:     MESSAGE_HANDLER(WM_PAINT,     OnPaint)
121:     MESSAGE_HANDLER(WM_COMMAND,   OnCommand)
122:     MESSAGE_HANDLER(WM_NCDESTROY, OnNcDestroy)
123:   END_MSG_HOOK_MAP()
124: 
125:   // message handlers
126: 
127:   //
128:   LRESULT OnPaint(UINT uMsg, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL & bHandled)
129:   {
130:     ATLASSERT(WM_PAINT == uMsg);
131:     uMsg;
132:     
133:     if(m_bUseWindowless && m_pUpdateLayeredWindow)
134:     {
135:       PAINTSTRUCT ps = { 0 };
136:       ::BeginPaint(GetHwndHooked(), &ps);
137: 
138:       _UpdateLayeredFlash();
139: 
140:       ::EndPaint(GetHwndHooked(), &ps);
141:     }
142:     else
143:     {
144:       bHandled = FALSE; // do not eat
145:     }
146: 
147:     return 0;
148:   }
149:   //
150:   LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL & bHandled)
151:   {
152:     ATLASSERT(WM_COMMAND == uMsg);
153:     uMsg;
154: 
155:     bHandled = FALSE; // do not eat
156: 
157:     if(!m_bUseWindowless || NULL == m_pUpdateLayeredWindow)
158:     {
159:       // window mode
160:       HWND hwndChild = GetWindow(GetHwndHooked(), GW_CHILD);
161: 
162:       // refer to " Flash WM_COMMAND wID's (*** window mode only ***) " at the end of code
163:       // to see what command can be sent to control the flash
164:       if(::IsWindow(hwndChild))
165:         return ::SendMessage(hwndChild, WM_COMMAND, wParam, lParam);
166:     }
167: 
168:     return 0;
169:   }
170: 
171:   LRESULT OnNcDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL & bHandled)
172:   {
173:     ATLASSERT(WM_NCDESTROY == uMsg);
174:     uMsg;
175: 
176:     bHandled = FALSE; // do not eat
177: 
178:     _Term();
179: 
180:     return 0;
181:   }
182: 
183: public:
184:   // c'tor
185:   CFlashconAxImplT()
186:     : m_pSF(NULL), m_pVO(NULL), m_pUpdateLayeredWindow(NULL),
187:       m_bUseWindowless(true), m_bySourceConstantAlpha(100), m_bUseTransparentKey(false)
188:   {
189:   }
190:   // d'tor
191:   ~CFlashconAxImplT()
192:   {
193:     _Term();
194:   }
195: 
196:   // properties
197: public:
198:   // 0 (transparent) ~ 100 (opaque)
199:   inline T & SetAlpahTransparency(BYTE byAlphaTransparency)
200:   {
201:     m_bySourceConstantAlpha = 100 < byAlphaTransparency ? 100 : byAlphaTransparency;
202:     
203:     return static_cast<T &>(*this);
204:   }
205:   //
206:   inline BYTE GetAlphaTransparency() const
207:   {
208:     return m_bySourceConstantAlpha; 
209:   }
210:   //
211:   T & SetTransparentKey(BOOL bEnable)
212:   {
213:     // TransparentKey setting here is a bit diffrent from what it is in .NET.
214:     // It simply make the user can't close the window, select it with the mouse
215:     // by setting WS_EX_TRANSPARENT style
216:     m_bUseTransparentKey = (FALSE != bEnable);
217: 
218:     if(::IsWindow(GetHwndHooked()))
219:     {
220:       if(m_bUseTransparentKey)
221:       {
222:         const DWORD dwExStyle = ::GetWindowLong(GetHwndHooked(), GWL_EXSTYLE);
223:         ::SetWindowLong(GetHwndHooked(), GWL_EXSTYLE, dwExStyle | WS_EX_TRANSPARENT);
224:       }
225:       else
226:       {
227:         const DWORD dwExStyle = ::GetWindowLong(GetHwndHooked(), GWL_EXSTYLE);
228:         ::SetWindowLong(GetHwndHooked(), GWL_EXSTYLE, dwExStyle & ~WS_EX_TRANSPARENT);
229:       }
230:     }
231: 
232:     return static_cast<T &>(*this);
233:   }
234:     
235:   // operations
236: public:
237:   //
238:   inline HRESULT GetControl(IShockwaveFlash ** ppFlash)
239:   {
240:     return AtlAxGetControl(GetHwndHooked(), (IUnknown **)ppFlash);
241:   }
242:   //
243:   inline HRESULT GetHost(IUnknown ** ppUnkContainer)
244:   {
245:     return AtlAxGetHost(GetHwndHooked(), ppUnkContainer);
246:   }
247:   //
248:   HRESULT CreateAxControl(HWND hwndParent, RECT & rcPos, HINSTANCE hInstance, IShockwaveFlash ** ppFlash, IUnknown ** ppUnkContainer = NULL)
249:   {
250:     if(NULL == ppFlash)
251:       return E_POINTER;
252: 
253:     if(!_Init())
254:       return E_FAIL;
255: 
256:     *ppFlash = NULL;
257: 
258:     if(NULL != ppUnkContainer)
259:       *ppUnkContainer = NULL;
260: 
261:     ////////////////////////////////////////////////////////////////////////////////////////////////////
262: 
263:     const DWORD dwStyle = WS_POPUP | WS_VISIBLE;
264:     const DWORD dwExStyle =  WS_EX_TOOLWINDOW | WS_EX_TOPMOST | WS_EX_LAYERED;
265: 
266:     HWND hwndCtrl = ::CreateWindowEx(dwExStyle, "AtlAxWin", NULL,
267:       dwStyle, rcPos.left, rcPos.top, rcPos.right - rcPos.left, rcPos.bottom - rcPos.top,
268:       hwndParent, NULL, hInstance, NULL);
269: 
270:     if(!::IsWindow(hwndCtrl))
271:       return E_FAIL;
272: 
273:     ////////////////////////////////////////////////////////////////////////////////////////////////////
274: 
275:     T * pT = static_cast<T *>(this);
276:     pT;
277: 
278:     HRESULT hr = pT->AttachAxControl(hwndCtrl, ppFlash, ppUnkContainer);
279: 
280:     return hr;
281:   }
282: 
283:   // overrides
284: public:
285:   //
286:   HRESULT AttachAxControl(HWND hWnd, IShockwaveFlash ** ppFlash, IUnknown ** ppUnkContainer = NULL)
287:   {
288:     ATLASSERT(::IsWindow(hWnd));
289: 
290:     if(NULL == ppFlash)
291:       return E_POINTER;
292: 
293:     if(!_Init())
294:       return E_FAIL;
295: 
296:     *ppFlash = NULL;
297: 
298:     if(NULL != ppUnkContainer)
299:       *ppUnkContainer = NULL;
300: 
301:     HRESULT hr = S_OK;
302: 
303:     ////////////////////////////////////////////////////////////////////////////////////////////////////
304: 
305:     // to create a Flash ActiveX control
306:     hr = ::CoCreateInstance(CLSID_ShockwaveFlash, NULL, CLSCTX_ALL, __uuidof(IShockwaveFlash), (void **)&m_pSF);
307:     if(FAILED(hr))
308:       return hr;
309: 
310:     ////////////////////////////////////////////////////////////////////////////////////////////////////
311: 
312:     // to store IViewObject interface for later usage
313:     hr = m_pSF->QueryInterface(__uuidof(IViewObject), (void **)&m_pVO);
314:     if(FAILED(hr) || NULL == m_pVO)