[Variable] COM & ATL by Silan Liu #1

출처 -> http://progtutorials.tripod.com/COM.htm

COM & ATL

Silan Liu

 

1.      COM Basics

1.1.        Service Control Manager (SCM)

A Windows program called Service Control Manager (SCM) does most of the job in COM server invoking. It finds the server through System Registry, runs it, has it create the COM object, sets up local/remote transparency, and returns an interface pointer to the client.

Then the client can directly invoke methods of the COM object through the pointer, and there is no middleware involved unless it is a remote server, in which case only RPC is involved.

1.2.        Interface IUnknown

All COM interfaces should inherit interface IUnknown:

 

interface IUnknown

{

HRESULT QueryInterface(REFIID iid, void** ppvObject);

ULONG AddRef();

ULONG Release();

}

One COM object may be used by multiple clients. The COM server maintains a reference count for each interface of the object. When one client asks to create an instance of the interface withCoCreateInstance or CoCreateInstanceEx, the COM server will call that interface’s method AddRef to increment the reference count.

When one client is finished with an interface, it should call its Release method to decrement the reference count. When the count reaches zero, the COM server should destroy the COM object.

In Visual Basic, a local COM object is automatically destroyed when leaving scope. To manually delete an object, say

 

Set objAccount = Nothing

1.3.        Global Unique ID (GUID)

Each coclass and interface has its guid, which is a 128-bit number. For easy use by the programmer, an easy-remember manifest constant is defined for each guid. In Visual C++ these constants are defined in a header file e.g. “Bank_i.c”, and some entries look like:

 

const IID IID_IGreet = {0x7A5E6E81,0x3DF8,0x11D3,{0x90,0x3D,0x00,0x10,0x5A,0xA4,0x5B,0xDC}};

 

const IID LIBID_BANKLib = {0x0FFBDAA1,0xFCA7,0x11D2,{0x8F,0xF4,0x00,0x10,0x5A,0xA4,0x5B,0xDC}};

 

const CLSID CLSID_Account = {0x0FFBDAAE,0xFCA7,0x11D2,{0x8F,0xF4,0x00,0x10,0x5A,0xA4,0x5B,0xDC}};

GUID constants such as IID_IGreet and CLSID_Account are not globally unique, but it does not matter because they live only in the scope of one application program. The compiler will read the interface definition file to convert the constant to the corresponding guid.

GUIDs for classes are of type CLSID, and all variables start with “CLSID_” followed by the class name, such as “CLSID_Account”. GUIDs for interfaces are of type IID,  and all start with “IID_” followed by the interface name such as “IID_IAccount”.

To convert between CLSID and unicode array:

 

CLSID clsid;

...

WCHAR * ostr;

HRESULT hr = StringFromCLSID(clsid, &ostr);

Program “Microsoft Visual Studio\Common\Tools\Guidgen.exe” is used to generate a guid. Choose the format of the guid and press button “Copy”. The generated guid will be in the clipboard.

You can also add it to the “Tools” menu with menu “Tools | Customize | Tools”.

1.4.        OLE/COM Object Viewer

OLE/COM Object Viewer goes through System Registry and collects all info about each coclass and their interfaces, and put them under one entry as their “user names”, which is the help string in the IDL file. You can find this entry under “All Objects” entry.

The “user name” entry stores the info about the coclass itself. Under it there are entries for all the interfaces of this class. Each entry stores the info about a specific interface.

OLD/COM Object Viewer can be started both from the “Start” menu and from Visual C++ menu “Tools”.

1.5.        System Registry

System Registry contains information about the computer. Under its “HKEY_CLASSES_ROOT” entry, all information about a coclass is stored. Under this entry, all coclasses are listed by their ProgIDs. Among the countless ProgID entries, there are two other entries: one named CLSID, under which all coclasses are listed by their guids; the other named Interface, under which all interfaces are listed by their guids.

ProgIDs are not guaranteed to be unique. They are used by some languages that can not directly refer to guids such as VBScript. VB can directly refer to guids, and can also optionally use ProgIDs. COM library provides to functions which can go through the System Registry and convert a ProgID to a CLSID or vice versa:

 

CLSID clsid;

CLSIDFromProgID(L"Cars.Jeep.1", &clsid);

 

LPOLESTR progid;

ProgIDFromCLSID(clsid, &progid);

We also need an entry to store some attributes about the whole server. For each server we can assign an AppID, under which we store all those atttributes such as AccessPermission,AuthenticationLevelDllSurogateLunchPermissionsRemoteServerName, etc. Then under each coclass entry under HKCR\CLSID, we add an AppID entry containing the AppID of the server.

When a coclass in invoked, the SCM reads the CLSID entry under HKCR\CLSID. If it finds an AppID entry, it will go further to find the AppID entry under HKCR\AppID. There it reads more about the server and knows how to deal with the server. For example, if SCM finds RemoteServerName entry there containing the name of another computer, it knows that the server is located oin another computer and it should contact the SCM of that computer.

When you call COM library functions such as CoCreateInstance passing a guid constant such as "CLSID_CoCar" or "IID_IRegistration", the compiler converts the guid contstant to the real guid by looking up the guid definition file *_i.c. At run time the real guid is sent to the API function.

¨    DLL server's entries in System Registry

A DLL server should have the following basic entries in the System Registry:

 

HKEY_CLASSES_ROOT\<ProgID>\CLSID = <clsid>

HKEY_CLASSES_ROOT\CLSID\<clsid> = <ProgID>

HKEY_CLASSES_ROOT\CLSID\<clsid>\InprocServer32 = <server full path>

You do not have to register your type library, for VC can directly #import from any directory, and VB and J++ can browse to find a *.tlb file. However, if you want to do it, you should add the following type library entries:

 

HKEY_CLASSES_ROOT\CLSID\<clsid>\TypeLib = <libid>

HKEY_CLASSES_ROOT\TypeLib\<libid> = <type library help string>

HKEY_CLASSES_ROOT\TypeLib\<libid>\1.0\0\Win32 = <type library full path>

HKEY_CLASSES_ROOT\TypeLib\<libid>\1.0\FLAGS = 0

HKEY_CLASSES_ROOT\TypeLib\<libid>\1.0\HELPDIR

When client calls CoCreateInstance with a CLSID and a IID, the COM run time will:

1.         go to the HKCR\CLSID\<guid>\InProcServer32 entry to find the location of the DLL server.

2.         load the DLL into process, call its exported DllGetClassObject function passing the coclass guid to get an IClassFactory pointer of the corresponding class factory;

3.         call the IClassFactory's CreateInstance method passing the IID of the interface to get a pointer of the interface.

You can see in the above process that the guids of the interfaces are only used inside the class factory. There is no need to store an entry for an interface in the System Registry.

¨    EXE server's entries in System Registry

A EXE server should have similar basic entries as a DLL server except it is LocalServer32:

 

HKEY_CLASSES_ROOT\<ProgID>\CLSID = <clsid>

HKEY_CLASSES_ROOT\CLSID\<clsid> = <ProgID>

HKEY_CLASSES_ROOT\CLSID\<clsid>\LocalServer32 = <server full path>

Besides these, it should have the following entries for each interface:

 

HKEY_CLASSES_ROOT\Interface\<iid>

HKEY_CLASSES_ROOT\Interface\ProxyStubClsid = <proxy/stub dll clsid>

HKEY_CLASSES_ROOT\Interface\ProxyStubClsid32 = <proxy/stub dll clsid>

If you use universal marshaller oleaut32.dll, which reads the registered type library and creates proxy/stub classes on the fly, you should put the CLSID of oleaut32.dll under ProxyStubClsid32, add the following interface entry, plus all the type library entries:

 

HKEY_CLASSES_ROOT\Interface\TypeLib = <type library libid>

For each interface you invoke, one proxy/stub object is instantiated. Therefore, you must set up a correspondence between an interface and its proxy/stub DLL server, so that when client invoke an interface, the SCM can find the corresponding proxy/stub DLL and create the corresponding proxy/stub object from it.

For this purpose, the System Registry stores the guids of the all interfaces of an EXE server under entry HKCR\Interface. Under each interface guid entry there is a ProxyStubClsid32 entry, which stores the CLSID of the custom proxy/stub DLL server which contains the proxy/stub coclass for that interface, or the universal marshaller oleaut32.dll.

Therefore, if you use the type library marshalling, you must register the type library under HKCR\TypeLib entry and each interface entry.

System Registry editor can be started at command line by typing “regedit”, or from OLE/COM Object Viewer in Visual C++.

 

2.      Unicode Handling

2.1.        Definitions of Different Type of Strings

¨    wchar_t

In C++ wchar_t is 16-bit wide character represented by unsigned short:

 

typedef wchar_t WCHAR;    // wc, 16-bit UNICODE character

typedef unsigned short wchar_t;

¨    LPOLESTR

In C++ LPOLESTR is a 16-bit unicode string represented by const unsigned short *:

 

typedef OLECHAR __RPC_FAR * LPOLESTR;

typedef WCHAR OLECHAR;

¨    LPCOLESTR

In C++ LPOLESTR is a constant 16-bit unicode string represented by const unsigned short *:

 

typedef const OLECHAR __RPC_FAR *LPCOLESTR;

¨    LPSTR

In C++ LPSTR is 8-bit multi-byte/ANSI string represented by char *

 

typedef CHAR *LPSTR, *PSTR;

typedef char CHAR;

¨    LPCSTR

In C++ LPCSTR is 8-bit multi-byte/ANSI string represented by const char *:

 

typedef CONST CHAR *LPCSTR, *PCSTR;

¨    TCHAR

In C++ TCHAR is 8-bit character represented by char:

 

typedef char TCHAR, *PTCHAR;

2.2.        CString <=> Multibyte String

 

#define m(x) ::MessageBox(NULL, x, "Test", MB_OK | MB_TOPMOST)

 

CString cstr("Hello the world");

 

    // CString::GetBuffer returns a pointer to its underlying buffer.

    LPSTR lpsz = cstr.GetBuffer(cstr.GetLength());

 

    // Both lpsz and cstr can access the underlying buffer.

m(lpsz);

m(cstr);

 

    // You can amend the buffer through cstr.

    cstr = "Hi Frank.";

m(lpsz);

 

    // You can also amend the buffer through lpsz, but you can't free it.

lpsz[8] = '!';

m(cstr);

    // free(lpsz); // Not allowed! Will cause run-time error!

 

    // After releasing the buffer, lpsz's content becomes undefined

cstr.ReleaseBuffer();

m(cstr);

 

    // If you want to avoid amending the original content of the CString,

    // make a copy.

    LPSTR lpszCopy = (LPSTR)malloc(strlen(lpsz));

memset(lpszCopy, 0, strlen(lpsz) + 1);

    strcpy(lpszCopy, lpsz);

m(lpszCopy);

2.3.        CString <=> Wide Character String

 

void CICPLoginDlg::CStringToWideChar(CString cstr, wchar_t * pwchar, int size)

{

    int cstrLen = cstr.GetLength();

ASSERT(cstrLen < MAX_LENGTH);

    MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, cstr.GetBuffer(cstrLen),

cstrLen, pwchar, size);

cstr.ReleaseBuffer();

}

2.4.        Allocating and Freeing BSTRs with API Functions

BSTR stands for basic string. It is a 16-bit Unicode with a prefix telling the count of the bytes in this string, therefore do not need NULL at the end.

When a server creates and passes out a BSTR, the server allocates memory space for the BSTR, while the client should deallocate the memory with a call to API function SysFreeString.

¨    Creating a new BSTR

 

BSTR bstr1 = SysAllocString(L"Hello world!");

OLECHAR * pOleStr = OLESTR("Good morning!");

BSTR bstr2 = SysAllocString(pOleStr);

¨    Modifying a BSTR

 

SysReAllocString(&bstr1, L"Good morning!");

¨    Freeing a BSTR

 

SysFreeString(bstr1);

2.5.        BSTR <=> CString

 

CString cstr(“Hello!”);

BSTR bstr = cstr.AllocSysString();

 

BSTR bstr = SysAllocString(L"Hello Frank!");

CString cstr(bstr);

2.6.        BSTR <=> Multibyte String

Second, use function wcstombs (wide character string to multibyte string) and mbstowcs (multibyte string to wide character string):

 

BSTR bstr1 = SysAllocString(L"Hellow world!");

char * buf[80];

wcstombs(buf, bstr1, 80);

SysFreeString(bstr1);

 

sprintf(buf, "Good morning!");

BSTR bstr2;

mbstowcs(bstr2, buf, 80);

2.7.        Multibyte String <=> Wide Character String

 

char * mbstr = "Hello world!";

int len1 = strlen(mbstr);

 

wchar_t wcbuf[80];

int len2 = sizeof(wcbuf) / sizeof(wchar_t);

::memset(wcbuf, 0, sizeof(wcbuf));

 

MultiByteToWideChar(

    CP_ACP,

    MB_PRECOMPOSED,

    mbstr,

    len1,

    wcbuf,

    len2);

 

char buf[300];

sprintf(buf, "wcbuf = %S", wcbuf);

::MessageBox(NULL, buf, NULL, MB_OK);

 

 

wchar_t * wcstr = L"Hello world!";

int len3 = wcslen(wcstr);

 

char mbbuf[300];

int len4 = sizeof(mbbuf);

::memset(mbbuf, 0, len4);

 

WideCharToMultiByte(

    CP_ACP,

    WC_COMPOSITECHECK,

    wcstr,

    len3,

    mbbuf,

    len4,

    NULL,

    NULL);

 

::MessageBox(NULL, mbbuf, NULL, MB_OK);

2.8.        Converting with ATL Macros

ATL provides a group of macros to convert between different types. Because one convertion involves a series of temporary variables to hold and swap the string buffers, the space is prepared by macroUSES_CONVERSION, which should be called before any conversion. They are defined in <atlconv.h>.

 

ANSI to ...

OLE to ...

TCHAR to ...

wchar_t to ...

A2BSTR

OLE2A

T2A

W2A

A2COLE

OLE2BSTR

T2BSTR

W2BSTR

A2CT

OLE2CA

T2CA

W2CA

A2CW

OLE2CT

T2COLE

W2COLE

A2OLE

OLE2CW

T2CW

W2CT

A2T

OLE2T

T2OLE

W2OLE

A2W

OLE2W

T2W

W2T

 

USES_CONVERSION;

MessageBox(NULL, W2A(bstr), NULL, MB_OK);

2.9.        MFC's BSTR Helper Class _bstr_t

MFC provides class _bstr_t to wrap BSTR. _bstr_t's constructor can take many types as input:

 

_bstr_t( ) throw( );

_bstr_t( const _bstr_t & s1 ) throw( );

_bstr_t( const char * s2 ) throw( _com_error );

_bstr_t( const wchar_t * s3 ) throw( _com_error );

_bstr_t( const _variant_t & var ) throw ( _com_error );

_bstr_t( BSTR bstr, bool fCopy ) throw ( _com_error );

Its assignment operator = is also overloaded for many types:

 

_bstr_t& operator=( const _bstr_t & s1 ) throw ( );

_bstr_t& operator=( const char * s2 ) throw( _com_error );

_bstr_t& operator=( const wchar_t * s3 ) throw( _com_error );

_bstr_t& operator=( const _variant_t & var ) throw( _com_error );

It has also overloaded +=, +, ! and all comparison operators.

To get a LPTSTR from _bstr_t:

 

  _bstr_t bstrt("Hello!");

  LPTSTR lp1 = (LPTSTR)bstrt;

  LPTSTR lp2 = bstrt.operator char *();

You can use _bstr_t anywhere expecting BSTR. If you like, you can also explicitly cast _bstr_t to BSTR:

 

_bstr_t bstrt("Hello!");

BSTR bstr = (BSTR)bstrt;

SysFreeString(bstr1);

_bstr_t object does not need to be deallocated. It is deallocated automatically when it leaves scope.

Class _bstr_t is contained in header file <comdef.h>.

2.10.     ATL's BSTR Helper Class CComBSTR

ATL also provides a wrapper class CComBSTR, which is more light than _bstr_t. CComBSTR wraps a BSTR data member m_str. Space for BSTR is allocated in its constructor and deallocated in the destructor.

Its constructor can take LPCOLESTR or LPCSTR as input. It can also designate the size of the buffer.

 

CComBSTR( int nSize );

CComBSTR( int nSize, LPCOLESTR sz );

CComBSTR( int nSize, LPCSTR sz );

CComBSTR( LPCOLESTR pSrc );

CComBSTR( LPCSTR pSrc );

CComBSTR( const CComBSTR& src );

Therefore you can say:

 

CComBSTR comBstr(“Hello!”);

To detach m_str from CComBSTR:

 

BSTR bstr = comBstr.Detach();

To attach a BSTR to a CComBSTR:

 

BSTR bstr = SysAllocString(L"Hello!");

CComBSTR comBstr;

comBstr.Attach(bstr);

To get a copy of m_str:

 

BSTR bstr = comBstr.Copy();

To get the address of m_str:

 

BSTR * pBstr = &comBstr.

To free m_str:

 

comBstr.Empty();

The overloaded assignment operator takes LPCOLESTR or LPCSTR as parameter. Therefore, to change the value of CComBSTR:

 

CComBSTR comBstr();

comBstr = L"Good morning!";

CComBSTR can only be casted to CString, which can be than casted to LPCSTR or LPCTSTR:

 

cstr = (CString)comBstr;

CComBSTR is contained in header file <atlbase.h>, which also contains other wrapper classes.

by toRoad™ | 2009/11/03 10:05 | ┗▷▶▷ Pragma | 트랙백 | 덧글(0)

[Mind] 세상

보편적이고 타당하다 생각할 너의 논리는 

네 머릿속 세상에서만 유효하다.

by toRoad™ | 2009/10/30 10:11 | toRoad™ :: Life | 트랙백 | 덧글(0)

[Life] 도움 안되는 다이어트 충고

+  Yahoo 에서 괜찮은 다이어트 정보를 찾았다.

Myth No. 1: 저녁 8시 이후에는 먹지 마라.

잘못된 충고: 낮시간에 섭취한 칼로리들은 모두 활동에 소모되는데 반해 밤에 섭취한 칼로리는 그대로 남아 지방으로 변한다는 논리로, 해가 진 뒤에는 음식물을 먹지 않는 다이어트법이다.

사실은: 칼로리는 시간별로 작용이 달라지지 않는다. 먹은 것을 소화하고 열량을 소모하는 과정은 아침이건 밤이건 동일하다. 밤에 먹은 음식이라고 모두 지방으로 변할 리 없다는 얘기다. 가급적 야식을 피해야 하는 이유는 소화기관에 부담을 줄 염려 때문이다. 먹는 시간보다는 총 섭취 칼로리를 조절하는 것이 적절하다. 

도움이 되는 충고: 밤시간이라고해서 배고픔을 억지로 참을 필요는 없다. 단, 체중조절을 목표로 하고 있다면 야참으로 아이스크림이나 과자 대신 과일이나 씨리얼을 먹도록 하자. 야식하는 사람일수록 비만일 확률이 높은 이유는 '과식' 때문이다. 규칙적인 식사를 하지 않다보니 한번에 많이 먹게 되는 것.


Myth No. 2: 적은 양을 자주 먹는 것이 신진대사를 활성화한다.

잘못된 충고: 낮은 칼로리, 소량의 음식을 자주 섭취하면 배고픔을 느끼지 않게 되고 신진대사가 활성화되어 같은 양을 먹고도 더 많은 칼로리를 소모할 수 있게 된다는 이야기를 누구나 한번쯤 들어봤을 것이다. 

사실은: 음식 섭취가 신진대사에 주는 영향은 미미하다. 간혹 카페인 섭취가 일시적으로 신진대사를 높이는 경우도 있지만, 체중감소에 도움이 될 정도는 아니다. 기초대사율(BMR)을 조절하는 것은 신체 구성과 사이즈. 근육이 많고 체격이 클수록 소모 칼로리가 늘어난다. 

도움이 되는 충고: 신진대사를 높이고 싶다면, 근육을 만들어라. 1파운드의 지방이 하루에 2~3칼로리를 소모하는데 비해, 근육 1파운드는 하루 14칼로리를 소모한다. 따라서 근력운동 없이 다이어트만 하는 것은 신진대사를 낮추는 셈이 된다. 음식조절과 함께 필라테스나 파워 요가, 덤벨운동 등을 병행할 것을 추천한다. 


Myth No. 3: 파스타와 같은 밀가루 음식을 먹으면 뚱뚱해진다.

잘못된 충고: 탄수화물을 섭취하면 몸에서 당분으로 바뀌고, 결국 지방으로 쌓이게 된다며 탄수화물 섭취를 극단적으로 줄이라는 조언을 한다.

사실은: 탄수화물 자체는 아무 죄가 없다. 살이 찌는 이유는 과도한 칼로리 섭취 때문이지 특정 영양성분 때문이 아니다. 탄수화물,지방,단백질 어떤 형태이건 적정 칼로리만 지킨다면 상관없다. 또한 탄수화물은 과일과 야채, 통곡물 등 건강에 좋은 음식에도 풍부한 성분이다. 

도움이 되는 충고: 밀가루 음식을 즐기는 것은 좋지만, 적정량만 먹도록 조절할 것. 파스타에는 야채를 곁들이고 토마토 소스를 부어 먹는 것이 건강에 도움이 된다. 


Myth No. 4: 커피가 체중조절을 돕는다.

잘못된 충고: 커피 속 카페인이 식욕을 줄이고 신진대사를 활성화시켜 살이 잘 빠지게 한다는 조언.

사실은: 커피를 마시면 일시적으로 식욕이 사라진 듯 느낄 수 있으나, 효과가 오래가지는 않는다. 하루 한두잔 정도의 커피는 체중을 줄이는데 전혀 도움이 되지 않는다. 그렇다고 하루 4~7잔씩 마시면 불면증, 고혈압, 심박수 증가, 불안증 등을 유발할 위험이 있으니 삼가하는 편이 좋다.

도움이 되는 충고: 커피 애호가라면 하루 한두잔을 크림이나 설탕 없이 즐기는 것이 다이어트를 방해하지 않는다. 모카나 카라멜 라떼같은 달짝지근한 커피들은 300칼로리가 넘어 다이어트에 도움이 되기는 커녕 칼로리 과다의 원인이 된다. 커피를 많이 마셔 불면증 증세가 오면, 식욕을 자극하는 호르몬이 분비되어 섭취 칼로리가 늘어나는 결과를 낳게 된다. 



Myth No. 5: 우유를 많이 마시면 체중 감소에 도움이 된다.


잘못된 충고: 칼슘은 지방 분해를 돕기 때문에, 우유를 많이 마시면 살이 빠지게 된다는 조언. 

사실은: 유제품은 결코 마법같은 효과를 가져올 수 없다. 오히려 유제품을 많이 섭취하는 사람일수록 섭취 칼로리가 높다는 연구 결과도 나온 바 있다. 일반적으로 전문가들은 유제품 섭취와 다이어트 사이에 별 상관관계가 없다고 설명한다. 

도움이 되는 충고: 다이어트 중이라면 저지방 우유를 마시자. 지방도 줄이고 칼로리 섭취도 줄이면서 칼슘을 섭취할 수 있는 방법이다. 50세 이하 성인이라면 1,000밀리그램(우유 세 컵 분량), 50세 이상은 1,200밀리그램씩의 칼슘을 섭취하는 것이 좋다. 우유를 먹으면 소화가 잘 되지 않는다면 두유, 오렌지 주스, 푸른잎 채소, 생선 등으로 칼슘을 섭취하자.


Myth No. 6: 섭취 칼로리를 제한하는 것이 체중을 줄이는 최선의 방법이다.


잘못된 충고: 먹는 양을 줄이고 칼로리를 제한하는 것 이외에는 체중을 줄일 수 있는 별다른 방법은 없다고 단언하는 경우.

사실은: 먹는 양을 줄이면 물론 체중이 줄어든다. 하지만 그 효과는 일시적일 뿐, 다시 정상적인 식생활로 돌아오면 체중은 다시 늘어나기 마련이다. 체중을 줄이고 이를 계속 유지하고 싶다면 애초부터 무리하게 먹는 것을 제한하는 다이어트는 하지 않는 편이 낫다. 

도움이 되는 충고: 일주일동안 사과만 먹는다거나 하는 식의 일시적 식이요법은 장기적으로 전혀 도움이 되지 않는다. 가장 현명한 방법은 먹는 습관을 바꾸는 것. 계속 지킬 수 있는 방식으로 식단을 바꾸고, 규칙적인 생활을 하고, 지속적으로 걷기 등 가벼운 운동을 하자. 


1차 출처: diet myths busted

2차 출처:

by toRoad™ | 2009/10/25 18:16 | toRoad™ :: Life | 트랙백 | 덧글(0)

[Movie] 람보

람보를 봤다.



첫번째 감상은 무난하다 였다.

요즘의 영화 추세에 비교해볼때 제법 자극적인 장면이 포함되어 있으면서도...
거기에 휘둘려 영화의 흐름을 끊거나 삼천포로 빠지는 일은 없었다.

두번째 감상은 안타까움이었다.

비단 전쟁뿐이겠냐 만은...
어느 한가지에서 극단으로 치닫아 버린 인간은 그 이후에 무엇도 예전같지 않게 된다.
4편의 영화속에서 람보는... 들어서버린 길을 돌아설 수 없음에 고뇌하고 끝네 운명이려니 받아들여 버린다.

관심을 가져본적도 없지만 새삼 전쟁에서 입은 심적 상처에 괴로워하는 사람들이 더 없이 안되어 보였다



람보 5편이 나온다면...

영화의 주제가 한결 같음에 따라 그 주제적 한계성이 영화의 발전을 허용할 수 없는 단계인 것으로 생각된다.
나와준다면 고맙겠지만... 무언가 바랄 수는 없으리라...

개인적으로는 스텔론 형님이 뭉클한 감동을 줄 수 있는 영화를 한편 제작해 주셨으면 한다.

그 정도 내공은 있다고 본다.


PS
-> 4편 마지막 장면에 고향으로 돌아온 람보가 길을 걸어가는 장면이 있다.
-> 적당히 걸어가다 끝나려니 했는데....
-> 끝까지 걸어가 버렸다. 걸어가면서 무슨 생각을 했는지 관심이 있다. @_@

by toRoad™ | 2009/09/13 13:00 | ┗▷▶▷ Cinema | 트랙백 | 덧글(0)

[ETC] Way of Capture

http://gpalem.web.officelive.com/screencap.html

Capture 를 하기 위한 3가지 방법에 대한 소개글...

by toRoad™ | 2009/07/31 11:58 | ┗▷▶▷ Pragma | 트랙백 | 덧글(0)

◀ 이전 페이지          다음 페이지 ▶