2010년 3월 10일 수요일

바깥 테두리 투명 처리

SetWindowRgn 란 함수로 처리한단다..

간단하게 예제로 보면

 //원형 시계

//ExClock.c
#include <windows.h>
#include <stdlib.h>
#include <time.h>

#define CLOCKTIMER 1
#define CLOCKSIZE 100

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
VOID CALLBACK TimeProc(HWND hwnd,UINT iMsg,UINT wParam,DWORD lParam);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
				   PSTR szCmdLine, int iCmdShow)
{
	static char szAppName[] = "ExClock";
	HWND        hwnd;
	MSG         msg;
	WNDCLASSEX  wndclass;
	int cx,x;

	wndclass.cbSize        = sizeof(wndclass);
	wndclass.style         = CS_HREDRAW | CS_VREDRAW;
	wndclass.lpfnWndProc   = WndProc;
	wndclass.cbClsExtra    = 0;
	wndclass.cbWndExtra    = 0;
	wndclass.hInstance     = hInstance;
	wndclass.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
	wndclass.hCursor       = LoadCursor(NULL, IDC_ARROW);
	wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wndclass.lpszMenuName  = NULL;
	wndclass.lpszClassName = szAppName;
	wndclass.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);

	RegisterClassEx(&wndclass);
	//스크린의 가로 크기를 얻는다.
	cx=GetSystemMetrics(SM_CXFULLSCREEN);
	x=cx-CLOCKSIZE;

	hwnd = CreateWindow(szAppName,
						"원형시계 예제:ExClock",
						WS_POPUP | WS_VISIBLE,
						x,
						0,
						CLOCKSIZE,
						CLOCKSIZE,
						NULL,
						NULL,
						hInstance,
						NULL);

	ShowWindow(hwnd, iCmdShow);
	UpdateWindow(hwnd);

	while(GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
	HDC         hdc;
	PAINTSTRUCT ps;
	HBRUSH hBrush,oldBrush;
	HPEN   hPen,oldPen;
	HRGN rgn;
	switch(iMsg)
	{
	case WM_CREATE:
		SetTimer(hwnd,CLOCKTIMER,100,(TIMERPROC)TimeProc);
		rgn=CreateRoundRectRgn(0,0,CLOCKSIZE,CLOCKSIZE,CLOCKSIZE,CLOCKSIZE);
		SetWindowRgn(hwnd,rgn,FALSE);
		return 0;
	case WM_PAINT:
		hdc = BeginPaint(hwnd, &ps);
		hBrush=CreateSolidBrush(RGB(0,0,200));
		hPen=CreatePen(PS_SOLID,3,RGB(200,200,91));
		oldBrush=SelectObject(hdc,hBrush);
		oldPen=SelectObject(hdc,hPen);

		RoundRect(hdc,0,0,CLOCKSIZE,CLOCKSIZE,CLOCKSIZE,CLOCKSIZE);

		SelectObject(hdc,CreateSolidBrush(RGB(0,0,0)));
		RoundRect(hdc,15,30,85,60,20,20);
		SelectObject(hdc,oldBrush);
		SelectObject(hdc,oldPen);
		DeleteObject(hBrush);
		DeleteObject(hPen);
		EndPaint (hwnd, &ps) ;
		return 0;
	case WM_DESTROY:
		KillTimer(hwnd,CLOCKTIMER);
		PostQuitMessage(0);
		return 0;
	}
	return DefWindowProc(hwnd, iMsg, wParam, lParam);
}

VOID CALLBACK TimeProc(HWND hwnd,UINT iMsg,UINT wParam,DWORD lParam)
{
	time_t curtime;
	struct tm cur;
	char curdate[80];
	HDC hdc;
	time(&curtime);
	cur=*localtime(&curtime);
	wsprintf(curdate,"%02d:%02d:%02d",cur.tm_hour,cur.tm_min,cur.tm_sec);
	hdc=GetDC(hwnd);
	SetBkColor(hdc,RGB(0,0,0));
	SetTextColor(hdc,RGB(255,255,0));
	TextOut(hdc,20,37,curdate,strlen(curdate));
	ReleaseDC(hwnd,hdc);
}
 

2010년 3월 8일 월요일

Dialog를 작업표시줄(task bar)에서 숨기려면

Dialog기반 프로그램을 작업표시줄에서 감추고 싶다면, 간단하게 Window Style을 수정해 주면 된다.

  1. LRESULT CMainDlg::OnInitDialog(  
  2.     UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)  
  3. {  
  4.     ...  
  5.     ModifyStyleEx( WS_EX_APPWINDOW,WS_EX_TOOLWINDOW,0 );  
  6.     return TRUE;  
  7. }  

문제는!!
이렇게 되면 Alt+Tab으로는 이 window를 선택할 수 없다는 점이다. 어쩌다 포커스를 잃게되면, window를 다시 찾기 상당히 귀찮아진다.

두시간의 삽질-_-을 통해 꽁수를 부려봤다. 좀 더 좋은 방법이 있다면 알려주시길~
WTL기반으로 작업했지만, MFC라도 약간만 응용하면 적용할 수 있다. (오히려 더 쉽게)

한줄요약: 작업표시줄에서는 나타나지 않으면서, Alt + Tab을 통해 활성화 되는 Dialog를 만들어 보자.

1. 바보-_- 윈도를 하나 만들자. (MFC라면 CWnd를 쓰면 되므로 이 과정은 생략)

  1. class CInvisibleWnd : public CWindowImpl<CInvisibleWnd >  
  2. {  
  3. public:  
  4.     DECLARE_WND_CLASS(NULL);  
  5.  
  6.     BEGIN_MSG_MAP(CInvisibleWnd)  
  7.     END_MSG_MAP()  
  8. };  

2. WTL이라면 Run함수에서 Dialog를 생성할 것이다. (MFC라면 CWinApp::InitInstance)
이때, Dialog의 부모로 바보윈도를 설정해 준다. 눈치 채셨겠지만, 이 꽁수의 핵심은 Dialog의 부모로 설정한 바보윈도는 화면에 표시되면 안된다는 점이다.

  1. int Run(LPTSTR /*lpstrCmdLine*/ = NULL, int nCmdShow = SW_SHOWDEFAULT)  
  2. {  
  3.     ...  
  4.  
  5.     CInvisibleWnd wndInvisible;  
  6.     wndInvisible.Create( NULL, 0, NULL, WS_OVERLAPPEDWINDOW );  
  7.     CMainDlg dlgMain;  
  8.     if ( dlgMain.Create( wndInvisible ) == NULL )  
  9.     {  
  10.         ATLTRACE(_T("Main dialog creation failed!\n"));  
  11.         return 0;  
  12.     }  
  13.  
  14.     dlgMain.ShowWindow(nCmdShow);  
  15.     int nRet = theLoop.Run();  
  16.     _Module.RemoveMessageLoop();  
  17.  
  18.     if ( wndInvisible.IsWindow() )  
  19.         wndInvisible.DestroyWindow();  
  20.  
  21.  
  22.     return nRet;  
  23. }  

그렇다. 바보 윈도는 화면에 표시되지 않고 있으니 작업표시줄에 나타나지 않지만, 인스턴스가 있으므로 Alt + Tab을 치면 나타난다! 그 인스턴스를 활성화 시켜주면 자식윈도로 등록된 Dialog가 활성되는 원리.
중요한점은, 프로그램 종료 시점에서 바보윈도또한 소멸시켜 줘야 한다는 거!

MFC라면 좀 더 쉽다. CDialog를 생성할때, 바보 윈도를 생성자의 parameter로 넘겨주기만 하면된다.
(물론, 소멸은 신경써줘야 한다.)

  1. BOOL CComaApp::InitInstance()  
  2. {  
  3.     ...  
  4.  
  5.     CWnd wndInvisible;  
  6.     LPCTSTR pstrOwnerClass = AfxRegisterWndClass(0);  
  7.  
  8.     if (!wndInvisible.CreateEx(0,   
  9.                             pstrOwnerClass,   
  10.                             _T(""),  
  11.                             WS_OVERLAPPEDWINDOW ,   
  12.                             CW_USEDEFAULT,  
  13.                             CW_USEDEFAULT,  
  14.                             CW_USEDEFAULT,  
  15.                             CW_USEDEFAULT,  
  16.                             NULL,   
  17.                             0 ))  
  18.     {  
  19.         TRACE(_T("failed to create invisible window"));  
  20.         return FALSE;  
  21.     }  
  22.  
  23.     CMainDlg dlg(&wndInvisible);  
  24.     
  25.     m_pMainWnd = &dlg;  
  26.     dlg.DoModal();  
  27.  
  28.     if (wndInvisible.m_hWnd != NULL)  
  29.         wndInvisible.DestroyWindow();  
  30. }  

3. 이제 OnInitDialog에서 ModifyStyleEx( WS_EX_APPWINDOW,0 ); 해주면 된다.

꽁수 끄읏!

2010년 3월 4일 목요일

com 모듈을 웹에서 사용하는 방법

웹에서 com모듈을 바로 불러쓰는 형태는 바람직한 형태는 아닌거 같지만

ActiveX의 형태를 벗어나고, 크로스 브라우징의 측면에서 보면 꽤 괜찮은 선택인 것 같다..

우선 com모듈을 오류없이 불러 쓸려면 레지스터리 조작이 필수적이다.

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Ext\PreApproved


이 위치에 키값을 저장시키면 된다.


그리고 com모듈을 만들때 IObjectSafety interface를 추가해줘야 한다.
MFC와 ATL 방식이 있는데.. 난 ATL을 쓰므로 MFC는 패스~

 #include <atlctl.h>


class ATL_NO_VTABLE {customclass} :

...

public IObjectSafetyImpl<{customclass},

INTERFACESAFE_FOR_UNTRUSTED_CALLER |

INTERFACESAFE_FOR_UNTRUSTED_DATA>

....


BEGIN_COM_MAP({customclass})

...

COM_INTERFACE_ENTRY(IObjectSafety)

END_COM_MAP()

 이렇게 하면 된다

참!! com project에서 바로 레지스터리에 추가하는 것도 좋은 방법인거 같다.