char szProgrampath[_MAX_PATH], szDrive[_MAX_DRIVE], szDir[_MAX_DIR];
GetModuleFileName( NULL, szProgrampath, _MAX_PATH);
_splitpath(szProgrampath, szDrive, szDir, NULL, NULL);
// 멤버변수 m_strPath에 담는다.
m_strPath.Format("%s%s", szDrive, szDir);
MFC
- 현재 모듈의 실행경로 얻어오기 2009.02.13
- 프로세스 실행시키고 작업이 완료되기까지 기다리기 2009.02.13
- ActiveX 컨트롤 테스트 인증서 2009.02.13
- ActiveX에서 IObjectSafety 구현하기(MFC) 2009.02.13
- 다중모니터 해상도 변경 2009.01.16
- Explorer.exe 오류발생시 트레이아이콘 다시 보이게 하기 2008.11.27 1
- 멀티라인헤더 및 배경색 추가 리스트콘트롤 - CListCtrlEx 2008.11.26
현재 모듈의 실행경로 얻어오기
2009. 2. 13. 10:25
프로세스 실행시키고 작업이 완료되기까지 기다리기
2009. 2. 13. 10:15
프로세스를 실행시키고.. 해당프로세스의 작업이 완료되었는지 기다린뒤 다음 코드를 수행하는 루틴
CString strDir;
char szDrive[_MAX_DRIVE], szDir[_MAX_DIR];
_splitpath(g_strFilePath.GetBuffer(g_strFilePath.GetLength()),szDrive,szDir,NULL,NULL);
strDir.Format("%s%s",szDrive,szDir);
SHELLEXECUTEINFO sei = {0};
sei.cbSize = sizeof (SHELLEXECUTEINFO);
sei.fMask = SEE_MASK_NOCLOSEPROCESS;
sei.lpVerb = "open";
sei.lpFile = g_strFilePath;
sei.lpDirectory = strDir.GetBuffer(strDir.Length());
sei.lpParameter = "test.txt -t.."
sei.nShow = SW_SHOWNORMAL;
if (ShellExecuteEx (&sei))
{
WaitForSingleObject (sei.hProcess, INFINITE);
}
// 익스플로러 띄우기..
ShellExecute(NULL, "open", "iexplore.exe", "http://dynaforce.tistory..com", NULL, SW_SHOWNORMAL);
////////////////////////////////////////////////////////////////////////////////////////////
WaitForSingleObject앞에
WaitForInputIdle(sei.hProcess, INFINITE);//해당프로그램이 초기화완료될때까지 대기
프로그램의 초기화 시간이 긴 경우 사용
ps. ShellExecuteEx안에서 CreateProcess를 내부적으로 호출
CString strDir;
char szDrive[_MAX_DRIVE], szDir[_MAX_DIR];
_splitpath(g_strFilePath.GetBuffer(g_strFilePath.GetLength()),szDrive,szDir,NULL,NULL);
strDir.Format("%s%s",szDrive,szDir);
SHELLEXECUTEINFO sei = {0};
sei.cbSize = sizeof (SHELLEXECUTEINFO);
sei.fMask = SEE_MASK_NOCLOSEPROCESS;
sei.lpVerb = "open";
sei.lpFile = g_strFilePath;
sei.lpDirectory = strDir.GetBuffer(strDir.Length());
sei.lpParameter = "test.txt -t.."
sei.nShow = SW_SHOWNORMAL;
if (ShellExecuteEx (&sei))
{
WaitForSingleObject (sei.hProcess, INFINITE);
}
// 익스플로러 띄우기..
ShellExecute(NULL, "open", "iexplore.exe", "http://dynaforce.tistory..com", NULL, SW_SHOWNORMAL);
////////////////////////////////////////////////////////////////////////////////////////////
WaitForSingleObject앞에
WaitForInputIdle(sei.hProcess, INFINITE);//해당프로그램이 초기화완료될때까지 대기
프로그램의 초기화 시간이 긴 경우 사용
ps. ShellExecuteEx안에서 CreateProcess를 내부적으로 호출
ActiveX 컨트롤 테스트 인증서
2009. 2. 13. 10:05
ActiveX 컨트롤 테스트 인증서
밑에 글(ActiveX 컨트롤에서 IObjectSafety 구현하기)에서 개인개발자나 시험용으로 만든 ActiveX 컨트롤을 컨테이너(IE)에서 사용할 때, 인증문제에 대한 것이 있었다.
이 파일은 그 문제를 잠시나마 해결하기 위해 ActiveX컨트롤에 인증서를 포함하여 Cab파일을 작성하게 하는 프로그램이다.
테스트 인증서 작성 -> Cab 작성 -> SignCode -> Check 등의 작업이 배치파일(sign50.bat)로 작성되어 있다.
inf파일을 문법에 맞게 구성한 후, sign50.bat를 실행하면 작성된다.
Test.html은 웹페이지에서 ActiveX 컨트롤을 사용하는 예제이고, 이 압축파일은 미니프로제트를 수행했을때 만들었던 ActiveX 컨트롤을 포함하고 있다.
--------------------------------------------------------------------------
배포
1) ActiveX 컨트롤을 각 PC에 복사
2) 그 컨트롤을 레지스트리에 등록
3) 필요한 DLL이 있다면 복사
=> 자동으로...
Cab 파일을 통해 위의 내용들을 자동화 시켜줌...
1) .inf 파일 작성
2) .ocx 파일과 .inf 파일을 .cab 파일로 압축
3) .cab 파일을 서명
4) .cab 파일을 웹페이지에 등록
//
1) .inf 파일 생성
=> VC 6.0 제공이 안됨...
=> 배포될 .ocx및 dll의 정보를 담고 있다...
2) .cab 파일 생성
=> cabarc.exe 유틸리티를 통해 생성...
cabarc.exe N test.cab test.ocx test.inf (step1.bat)
=> test.cab 파일 생성( 압축파일..)
3) .cab 서명
makecert -sv "mycert.pvk" -n "CN=TEST ActiveX" mycert.cer
=> 대화상자 생성 => 암호 입력 => 개인 키 파일(mycert.pvk, mycert.cer)
생성
cert2spec mycert.cer mycert.spc
=> mycert.cer로부터 mycert.spc를 생성 ( makespc.bat 사용)
컨트롤 서명
signcode -v mycert.pvk -spc mycert.spc test.cab
=> test용 .cab 파일을 인증하는 코드
인증기관에서 제대로된 인증을 받으려면 위 명령줄에 -t 인증기관 URL을 추가
setreg -q 1 TRUE
=> test용 인증서가 인식되도록 설정
chktrust test.cab
=> CAB 파일이 올바르게 서명되었는지 확인...(step2.bat..)
밑에 글(ActiveX 컨트롤에서 IObjectSafety 구현하기)에서 개인개발자나 시험용으로 만든 ActiveX 컨트롤을 컨테이너(IE)에서 사용할 때, 인증문제에 대한 것이 있었다.
이 파일은 그 문제를 잠시나마 해결하기 위해 ActiveX컨트롤에 인증서를 포함하여 Cab파일을 작성하게 하는 프로그램이다.
테스트 인증서 작성 -> Cab 작성 -> SignCode -> Check 등의 작업이 배치파일(sign50.bat)로 작성되어 있다.
inf파일을 문법에 맞게 구성한 후, sign50.bat를 실행하면 작성된다.
Test.html은 웹페이지에서 ActiveX 컨트롤을 사용하는 예제이고, 이 압축파일은 미니프로제트를 수행했을때 만들었던 ActiveX 컨트롤을 포함하고 있다.
--------------------------------------------------------------------------
배포
1) ActiveX 컨트롤을 각 PC에 복사
2) 그 컨트롤을 레지스트리에 등록
3) 필요한 DLL이 있다면 복사
=> 자동으로...
Cab 파일을 통해 위의 내용들을 자동화 시켜줌...
1) .inf 파일 작성
2) .ocx 파일과 .inf 파일을 .cab 파일로 압축
3) .cab 파일을 서명
4) .cab 파일을 웹페이지에 등록
//
1) .inf 파일 생성
=> VC 6.0 제공이 안됨...
=> 배포될 .ocx및 dll의 정보를 담고 있다...
2) .cab 파일 생성
=> cabarc.exe 유틸리티를 통해 생성...
cabarc.exe N test.cab test.ocx test.inf (step1.bat)
=> test.cab 파일 생성( 압축파일..)
3) .cab 서명
makecert -sv "mycert.pvk" -n "CN=TEST ActiveX" mycert.cer
=> 대화상자 생성 => 암호 입력 => 개인 키 파일(mycert.pvk, mycert.cer)
생성
cert2spec mycert.cer mycert.spc
=> mycert.cer로부터 mycert.spc를 생성 ( makespc.bat 사용)
컨트롤 서명
signcode -v mycert.pvk -spc mycert.spc test.cab
=> test용 .cab 파일을 인증하는 코드
인증기관에서 제대로된 인증을 받으려면 위 명령줄에 -t 인증기관 URL을 추가
setreg -q 1 TRUE
=> test용 인증서가 인식되도록 설정
chktrust test.cab
=> CAB 파일이 올바르게 서명되었는지 확인...(step2.bat..)
ActiveX에서 IObjectSafety 구현하기(MFC)
2009. 2. 13. 09:57
보안문제 해결하기
ActiveX 컨트롤 IE에서 보여주기 위해 사용하는 경우에 보안관련 메세지 박스들이 나타나게 된다. 이 컨트롤 자체가 신뢰할 수 있는 제작사 또는 개발자에 의해서 개발된 것인가 하는 것과 ActiveX 컨트롤에 매개변수를 넘기는 경우와 같이 ActiveX 스크립트를 사용하는 경우에는 안전한 스크립트인지 확인하라는 경우이다.
전자는 code signing을 통해 보장받을 수 있으며, 후자의 경우는 IObjectSafefy 인터페이스를 구현함으로써 보장받을 수 있다.
전자의 경우는 VeriSign에서 몇백달러를 지불하는데, 시험용이나 개인개발자들은 시험용 인증서를 만들어서 사용할 수 있다.
지금 여기서는 후자의 경우 해결방안에 대해서 기술하고자 한다.
Test라는 이름으로 구현해보자!
cathelp.cpp와 cathelp.h를 프로젝트에 포함시킨 후,
DllRegisterServer()를 다음과 같이 수정한다.
STDAPI DllRegisterServer(void)
{
HRESULT hr = NOERROR;
AFX_MANAGE_STATE(_afxModuleAddrThis);
if (!AfxOleRegisterTypeLib(AfxGetInstanceHandle(), _tlid))
return ResultFromScode(SELFREG_E_TYPELIB);
if (!COleObjectFactoryEx::UpdateRegistryAll(TRUE))
return ResultFromScode(SELFREG_E_CLASS);
hr = CreateComponentCategory(CATID_SafeForScripting, L"Controls that are safely scriptable");
if (FAILED(hr))
{
;// OutputDebugString("Failed to create component category (scriptable)!n");
}
hr = CreateComponentCategory(CATID_SafeForInitializing, L"Controls safely initializable from persistent data");
if (FAILED(hr))
{
;// OutputDebugString("Failed to create component category (persistence)!n");
}
hr = RegisterCLSIDInCategory(CTestCtrl::guid, CATID_SafeForScripting);
if (FAILED(hr))
{
;// OutputDebugString("Failed to register control as safe for scripting!n");
}
hr = RegisterCLSIDInCategory(CTestCtrl::guid, CATID_SafeForInitializing);
if (FAILED(hr))
{
;// OutputDebugString("Failed to register control as safe for initializing!n");
}
return NOERROR;
}
DllUnregisterServer()를 아래와 같이 수정한다.
STDAPI DllUnregisterServer(void)
{
AFX_MANAGE_STATE(_afxModuleAddrThis);
if (!AfxOleUnregisterTypeLib(_tlid, _wVerMajor, _wVerMinor))
return ResultFromScode(SELFREG_E_TYPELIB);
if (!COleObjectFactoryEx::UpdateRegistryAll(FALSE))
return ResultFromScode(SELFREG_E_CLASS);
HRESULT hr = NOERROR;
hr = UnRegisterCLSIDInCategory(CTestCtrl::guid, CATID_SafeForScripting);
hr = UnRegisterCLSIDInCategory(CTestCtrl::guid, CATID_SafeForInitializing);
return NOERROR;
}
컨트롤이름ctrl.h 파일에 objsafe.h을 include한다.
그리고, 아래와 같이 추가한다.
class CTestCtrl : public COleControl
{
DECLARE_DYNCREATE(CTestCtrl)
BEGIN_INTERFACE_PART(ObjectSafety, IObjectSafety)
STDMETHOD(GetInterfaceSafetyOptions)(REFIID riid, DWORD __RPC_FAR *pdwSupportedOptions, DWORD __RPC_FAR *pdwEnabledOptions);
STDMETHOD(SetInterfaceSafetyOptions)(REFIID riid, DWORD dwOptionSetMask, DWORD dwEnabledOptions);
END_INTERFACE_PART(ObjectSafety)
DECLARE_INTERFACE_MAP();
마지막으로 cpp파일에 다음을 추가하면 된다.
STDMETHODIMP CTestCtrl::XObjectSafety::GetInterfaceSafetyOptions(
REFIID riid,
DWORD __RPC_FAR *pdwSupportedOptions,
DWORD __RPC_FAR *pdwEnabledOptions)
{
METHOD_PROLOGUE_EX(CTestCtrl, ObjectSafety)
if (!pdwSupportedOptions || !pdwEnabledOptions)
{
return E_POINTER;
}
*pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA;
*pdwEnabledOptions = 0;
if (NULL == pThis->GetInterface(&riid))
{
;// TRACE("Requested interface is not supported.n");
return E_NOINTERFACE;
}
// What interface is being checked out anyhow?
OLECHAR szGUID[39];
int i = StringFromGUID2(riid, szGUID, 39);
if (riid == IID_IDispatch)
{
// Client wants to know if object is safe for scripting
*pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER;
return S_OK;
}
else if (riid == IID_IPersistPropertyBag
|| riid == IID_IPersistStreamInit
|| riid == IID_IPersistStorage
|| riid == IID_IPersistMemory)
{
// Those are the persistence interfaces COleControl derived controls support
// as indicated in AFXCTL.H
// Client wants to know if object is safe for initializing from persistent data
*pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_DATA;
return S_OK;
}
else
{
// Find out what interface this is, and decide what options to enable
;// TRACE("We didn't account for the safety of this interface, and it's one we support...n");
return E_NOINTERFACE;
}
}
STDMETHODIMP CTestCtrl::XObjectSafety::SetInterfaceSafetyOptions(
REFIID riid,
DWORD dwOptionSetMask,
DWORD dwEnabledOptions)
{
METHOD_PROLOGUE_EX(CTestCtrl, ObjectSafety)
OLECHAR szGUID[39];
// What is this interface anyway?
// We can do a quick lookup in the registry under HKEY_CLASSES_ROOTInterface
int i = StringFromGUID2(riid, szGUID, 39);
if (0 == dwOptionSetMask && 0 == dwEnabledOptions)
{
// the control certainly supports NO requests through the specified interface
// so it's safe to return S_OK even if the interface isn't supported.
return S_OK;
}
// Do we support the specified interface?
if (NULL == pThis->GetInterface(&riid))
{
TRACE1("%s is not support.n", szGUID);
return E_FAIL;
}
if (riid == IID_IDispatch)
{
;// TRACE("Client asking if it's safe to call through IDispatch.n");
;// TRACE("In other words, is the control safe for scripting?n");
if (INTERFACESAFE_FOR_UNTRUSTED_CALLER == dwOptionSetMask && INTERFACESAFE_FOR_UNTRUSTED_CALLER == dwEnabledOptions)
{
return S_OK;
}
else
{
return E_FAIL;
}
}
else if (riid == IID_IPersistPropertyBag
|| riid == IID_IPersistStreamInit
|| riid == IID_IPersistStorage
|| riid == IID_IPersistMemory)
{
;// TRACE("Client asking if it's safe to call through IPersist*.n");
;// TRACE("In other words, is the control safe for initializing from persistent data?n");
if (INTERFACESAFE_FOR_UNTRUSTED_DATA == dwOptionSetMask && INTERFACESAFE_FOR_UNTRUSTED_DATA == dwEnabledOptions)
{
return NOERROR;
}
else
{
return E_FAIL;
}
}
else
{
TRACE1("We didn't account for the safety of %s, and it's one we support...n", szGUID);
return E_FAIL;
}
}
STDMETHODIMP_(ULONG) CTestCtrl::XObjectSafety::AddRef()
{
METHOD_PROLOGUE_EX_(CTestCtrl, ObjectSafety)
return (ULONG)pThis->ExternalAddRef();
}
STDMETHODIMP_(ULONG) CTestCtrl::XObjectSafety::Release()
{
METHOD_PROLOGUE_EX_(CTestCtrl, ObjectSafety)
return (ULONG)pThis->ExternalRelease();
}
STDMETHODIMP CTextCtrl::XObjectSafety::QueryInterface(
REFIID iid, LPVOID* ppvObj)
{
METHOD_PROLOGUE_EX_(CTestCtrl, ObjectSafety)
return (HRESULT)pThis->ExternalQueryInterface(&iid, ppvObj);
}
출처 : 미친병아리
ActiveX 컨트롤 IE에서 보여주기 위해 사용하는 경우에 보안관련 메세지 박스들이 나타나게 된다. 이 컨트롤 자체가 신뢰할 수 있는 제작사 또는 개발자에 의해서 개발된 것인가 하는 것과 ActiveX 컨트롤에 매개변수를 넘기는 경우와 같이 ActiveX 스크립트를 사용하는 경우에는 안전한 스크립트인지 확인하라는 경우이다.
전자는 code signing을 통해 보장받을 수 있으며, 후자의 경우는 IObjectSafefy 인터페이스를 구현함으로써 보장받을 수 있다.
전자의 경우는 VeriSign에서 몇백달러를 지불하는데, 시험용이나 개인개발자들은 시험용 인증서를 만들어서 사용할 수 있다.
지금 여기서는 후자의 경우 해결방안에 대해서 기술하고자 한다.
Test라는 이름으로 구현해보자!
cathelp.cpp와 cathelp.h를 프로젝트에 포함시킨 후,
DllRegisterServer()를 다음과 같이 수정한다.
STDAPI DllRegisterServer(void)
{
HRESULT hr = NOERROR;
AFX_MANAGE_STATE(_afxModuleAddrThis);
if (!AfxOleRegisterTypeLib(AfxGetInstanceHandle(), _tlid))
return ResultFromScode(SELFREG_E_TYPELIB);
if (!COleObjectFactoryEx::UpdateRegistryAll(TRUE))
return ResultFromScode(SELFREG_E_CLASS);
hr = CreateComponentCategory(CATID_SafeForScripting, L"Controls that are safely scriptable");
if (FAILED(hr))
{
;// OutputDebugString("Failed to create component category (scriptable)!n");
}
hr = CreateComponentCategory(CATID_SafeForInitializing, L"Controls safely initializable from persistent data");
if (FAILED(hr))
{
;// OutputDebugString("Failed to create component category (persistence)!n");
}
hr = RegisterCLSIDInCategory(CTestCtrl::guid, CATID_SafeForScripting);
if (FAILED(hr))
{
;// OutputDebugString("Failed to register control as safe for scripting!n");
}
hr = RegisterCLSIDInCategory(CTestCtrl::guid, CATID_SafeForInitializing);
if (FAILED(hr))
{
;// OutputDebugString("Failed to register control as safe for initializing!n");
}
return NOERROR;
}
DllUnregisterServer()를 아래와 같이 수정한다.
STDAPI DllUnregisterServer(void)
{
AFX_MANAGE_STATE(_afxModuleAddrThis);
if (!AfxOleUnregisterTypeLib(_tlid, _wVerMajor, _wVerMinor))
return ResultFromScode(SELFREG_E_TYPELIB);
if (!COleObjectFactoryEx::UpdateRegistryAll(FALSE))
return ResultFromScode(SELFREG_E_CLASS);
HRESULT hr = NOERROR;
hr = UnRegisterCLSIDInCategory(CTestCtrl::guid, CATID_SafeForScripting);
hr = UnRegisterCLSIDInCategory(CTestCtrl::guid, CATID_SafeForInitializing);
return NOERROR;
}
컨트롤이름ctrl.h 파일에 objsafe.h을 include한다.
그리고, 아래와 같이 추가한다.
class CTestCtrl : public COleControl
{
DECLARE_DYNCREATE(CTestCtrl)
BEGIN_INTERFACE_PART(ObjectSafety, IObjectSafety)
STDMETHOD(GetInterfaceSafetyOptions)(REFIID riid, DWORD __RPC_FAR *pdwSupportedOptions, DWORD __RPC_FAR *pdwEnabledOptions);
STDMETHOD(SetInterfaceSafetyOptions)(REFIID riid, DWORD dwOptionSetMask, DWORD dwEnabledOptions);
END_INTERFACE_PART(ObjectSafety)
DECLARE_INTERFACE_MAP();
마지막으로 cpp파일에 다음을 추가하면 된다.
STDMETHODIMP CTestCtrl::XObjectSafety::GetInterfaceSafetyOptions(
REFIID riid,
DWORD __RPC_FAR *pdwSupportedOptions,
DWORD __RPC_FAR *pdwEnabledOptions)
{
METHOD_PROLOGUE_EX(CTestCtrl, ObjectSafety)
if (!pdwSupportedOptions || !pdwEnabledOptions)
{
return E_POINTER;
}
*pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA;
*pdwEnabledOptions = 0;
if (NULL == pThis->GetInterface(&riid))
{
;// TRACE("Requested interface is not supported.n");
return E_NOINTERFACE;
}
// What interface is being checked out anyhow?
OLECHAR szGUID[39];
int i = StringFromGUID2(riid, szGUID, 39);
if (riid == IID_IDispatch)
{
// Client wants to know if object is safe for scripting
*pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER;
return S_OK;
}
else if (riid == IID_IPersistPropertyBag
|| riid == IID_IPersistStreamInit
|| riid == IID_IPersistStorage
|| riid == IID_IPersistMemory)
{
// Those are the persistence interfaces COleControl derived controls support
// as indicated in AFXCTL.H
// Client wants to know if object is safe for initializing from persistent data
*pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_DATA;
return S_OK;
}
else
{
// Find out what interface this is, and decide what options to enable
;// TRACE("We didn't account for the safety of this interface, and it's one we support...n");
return E_NOINTERFACE;
}
}
STDMETHODIMP CTestCtrl::XObjectSafety::SetInterfaceSafetyOptions(
REFIID riid,
DWORD dwOptionSetMask,
DWORD dwEnabledOptions)
{
METHOD_PROLOGUE_EX(CTestCtrl, ObjectSafety)
OLECHAR szGUID[39];
// What is this interface anyway?
// We can do a quick lookup in the registry under HKEY_CLASSES_ROOTInterface
int i = StringFromGUID2(riid, szGUID, 39);
if (0 == dwOptionSetMask && 0 == dwEnabledOptions)
{
// the control certainly supports NO requests through the specified interface
// so it's safe to return S_OK even if the interface isn't supported.
return S_OK;
}
// Do we support the specified interface?
if (NULL == pThis->GetInterface(&riid))
{
TRACE1("%s is not support.n", szGUID);
return E_FAIL;
}
if (riid == IID_IDispatch)
{
;// TRACE("Client asking if it's safe to call through IDispatch.n");
;// TRACE("In other words, is the control safe for scripting?n");
if (INTERFACESAFE_FOR_UNTRUSTED_CALLER == dwOptionSetMask && INTERFACESAFE_FOR_UNTRUSTED_CALLER == dwEnabledOptions)
{
return S_OK;
}
else
{
return E_FAIL;
}
}
else if (riid == IID_IPersistPropertyBag
|| riid == IID_IPersistStreamInit
|| riid == IID_IPersistStorage
|| riid == IID_IPersistMemory)
{
;// TRACE("Client asking if it's safe to call through IPersist*.n");
;// TRACE("In other words, is the control safe for initializing from persistent data?n");
if (INTERFACESAFE_FOR_UNTRUSTED_DATA == dwOptionSetMask && INTERFACESAFE_FOR_UNTRUSTED_DATA == dwEnabledOptions)
{
return NOERROR;
}
else
{
return E_FAIL;
}
}
else
{
TRACE1("We didn't account for the safety of %s, and it's one we support...n", szGUID);
return E_FAIL;
}
}
STDMETHODIMP_(ULONG) CTestCtrl::XObjectSafety::AddRef()
{
METHOD_PROLOGUE_EX_(CTestCtrl, ObjectSafety)
return (ULONG)pThis->ExternalAddRef();
}
STDMETHODIMP_(ULONG) CTestCtrl::XObjectSafety::Release()
{
METHOD_PROLOGUE_EX_(CTestCtrl, ObjectSafety)
return (ULONG)pThis->ExternalRelease();
}
STDMETHODIMP CTextCtrl::XObjectSafety::QueryInterface(
REFIID iid, LPVOID* ppvObj)
{
METHOD_PROLOGUE_EX_(CTestCtrl, ObjectSafety)
return (HRESULT)pThis->ExternalQueryInterface(&iid, ppvObj);
}
출처 : 미친병아리
다중모니터 해상도 변경
2009. 1. 16. 17:23
void MyChangeDisplaySettings()
{
DISPLAY_DEVICE dd;
DEVMODE dm;
int nDev = 2;
DWORD dwWidth[2] = {640, 640}; //첫번째 모니터는 1024*768로 만들고
DWORD dwHeight[2] = {480, 480}; //두번째 모니터는 800*600으로 만든다면....
for(int i=0; i < nDev; i++) {
//EnumDisplayDevices 함수를 이용하여 디스플레이 디바이스를 찾아야 합니다.
memset(&dd, 0, sizeof(DISPLAY_DEVICE));
dd.cb = sizeof(DISPLAY_DEVICE);
EnumDisplayDevices(NULL, i, &dd, 0); //i번째 모니터의 이름을 받아올 수 있습니다.
memset(&dm, 0, sizeof(DEVMODE));
dm.dmSize = sizeof(DEVMODE);
dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
dm.dmPelsWidth = dwWidth[i];
dm.dmPelsHeight = dwHeight[i];
if (ChangeDisplaySettingsEx((char*)dd.DeviceName, &dm, NULL, CDS_TEST, NULL) == DISP_CHANGE_SUCCESSFUL)
ChangeDisplaySettingsEx((char*)dd.DeviceName, &dm, NULL, CDS_FULLSCREEN, NULL);
}
}
Explorer.exe 오류발생시 트레이아이콘 다시 보이게 하기
2008. 11. 27. 15:03
Explorer.exe 가 오류가 발생하여 다시 시작됐을때, 트레이아이콘이 사라지게 된다.
이 문제를 해결하기 위해서는 다시 시작됐을때 메세지를 받아서 처리하면 된다.
h 파일에 함수를 하나 추가한다.
// 메세지 처리 함수
void OnTrayShow(WPARAM wParam, LPARAM lParam);
cpp 파일에 아래의 내용을 추가한다.
// 전역변수 추가
UINT g_uShellRestart = RegisterWindowMessage(__TEXT("TaskbarCreated"));
// 메세지 맵 추가
ON_REGISTERED_MESSAGE(g_uShellRestart, OnTrayShow)
// 메세지 처리
void CTrayTestDlg::OnTrayShow(WPARAM wParam, LPARAM lParam)
{
Shell_NotifyIcon(NIM_ADD, &m_nid/*NOTIFYICONDATA*/);
SendMessage(WM_SETICON, (WPARAM)TRUE, (LPARAM)m_nid.hIcon);
}
이 문제를 해결하기 위해서는 다시 시작됐을때 메세지를 받아서 처리하면 된다.
h 파일에 함수를 하나 추가한다.
// 메세지 처리 함수
void OnTrayShow(WPARAM wParam, LPARAM lParam);
cpp 파일에 아래의 내용을 추가한다.
// 전역변수 추가
UINT g_uShellRestart = RegisterWindowMessage(__TEXT("TaskbarCreated"));
// 메세지 맵 추가
ON_REGISTERED_MESSAGE(g_uShellRestart, OnTrayShow)
// 메세지 처리
void CTrayTestDlg::OnTrayShow(WPARAM wParam, LPARAM lParam)
{
Shell_NotifyIcon(NIM_ADD, &m_nid/*NOTIFYICONDATA*/);
SendMessage(WM_SETICON, (WPARAM)TRUE, (LPARAM)m_nid.hIcon);
}
멀티라인헤더 및 배경색 추가 리스트콘트롤 - CListCtrlEx
2008. 11. 26. 14:40
리스트콘트롤의 헤더에서 멀티라인 지원하는 클래스.
http://www.codeproject.com 에 있는 자료를 필요에 의해 짜집기 및 수정해서 만들었다.
사용법은 간단하다.
http://www.codeproject.com 에 있는 자료를 필요에 의해 짜집기 및 수정해서 만들었다.
사용법은 간단하다.
// 헤더파일 추가
#include "ListCtrlEx.h"
CListCtrl 멤버변수를 CListCtrlEx로 바꿔주고...
// 헤더 추가
LV_COLUMN lvcolumn;
lvcolumn.mask = LVCF_FMT|LVCF_SUBITEM|LVCF_TEXT|LVCF_WIDTH;
lvcolumn.fmt = LVCFMT_CENTER;
lvcolumn.cx = 0;
lvcolumn.pszText = " ";
m_ctrlList.InsertColumn(nIdx++, &lvcolumn);
lvcolumn.fmt = LVCFMT_RIGHT;
lvcolumn.cx = 100;
lvcolumn.pszText = "공사비용\n(만원)";
m_ctrlList.InsertColumn(nIdx++, &lvcolumn);
lvcolumn.fmt = LVCFMT_RIGHT;
lvcolumn.cx = 80;
lvcolumn.pszText = "공정률\n(%)";
m_ctrlList.InsertColumn(nIdx++, &lvcolumn);
// 모든 헤더가 추가된 후 마지막에 한줄 추가
m_ctrlList.Initializing(320, "견명조");
위와 같이 하면 헤더에 멀티라인 적용되며, 데이터는 한줄 번갈아가며 배경색이 적용된다.