천객만래 [千客萬來] (It has an interminable succession of visitors)

[개발/VC++] Visual C++에 관련된 유용한 코드 팁







Visual C++에 관련된 유용한 코드 팁
내용


1.Link: Knowledge Base 
2.다이알로그에 스킨 입히기 
3.투명 윈도우 만들기 
4.내 IP 얻는 방법 
5.트레이 아이콘 
6.패스 분리하는 방법 
7.FTP 관련 
8.Downloaded Program Files 폴더의 OCX 삭제방법 
9.디버깅 용도의 실행시간 출력 코드 
10.Trace Tip 
11.모니터 끄기 
12.프로세스간 데이터 교환 
13.Log 함수 
14.Ctrl+Esc, Alt+Tab, and Alt+Esc를 막는 법 
15.About box에 URL 링크 걸기 
16.특정 파일 오픈시 바로 프로그램 불러오기 
17.드래그 앤 드롭으로 파일 오픈 
18.app가 트레이에만 띄우도록 하려면 
19.single thread 어플리케이션에 취소 버튼 구현 
20.PC시간 셋팅하기
1 Link: Knowledge Base
Knowledge base : MFC 및 Visual C++ 프로그래밍에 대한 방대한 tip과 know-how를 담고 있다.

 

2 다이알로그에 스킨 입히기
void CDlgPictureDlg::OnPaint()  

    if (IsIconic()) 
    { 
        CPaintDC dc(this); // device context for painting 
 
        SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0); 
 
        // Center icon in client rectangle 
        int cxIcon = GetSystemMetrics(SM_CXICON); 
        int cyIcon = GetSystemMetrics(SM_CYICON); 
        CRect rect; 
        GetClientRect(&rect); 
        int x = (rect.Width() - cxIcon + 1) / 2; 
        int y = (rect.Height() - cyIcon + 1) / 2; 
 
        // Draw the icon 
        dc.DrawIcon(x, y, m_hIcon); 
    } 
    else 
    {     
        CWindowDC dc(this); 
        CDC memDC; 
        memDC.CreateCompatibleDC(&dc); 
        CBitmap bitmap; 
        BITMAP bm; 
        bitmap.LoadBitmap(IDB_BITMAP1);      <<-- 비트맵 이미지를 만들어야한다. 
        bitmap.GetBitmap(&bm); 
        CBitmap* pOld = memDC.SelectObject(&bitmap); 
        dc.BitBlt(5, 30, bm.bmWidth, bm.bmHeight, &memDC, 0, 0, SRCCOPY); 
        dc.SelectObject(pOld); 
        memDC.DeleteDC(); 
        CDialog::OnPaint(); 
    } 
  

3 투명 윈도우 만들기
BOOL CWin1Dlg::OnInitDialog() 

    CDialog::OnInitDialog(); 
  
    SLWA pSetLayeredWindowAttributes = NULL;     // 함수포인터 선언, 초기화. 
    HINSTANCE hmodUSER32 = LoadLibrary("USER32.DLL");  // 인스턴스 얻음. 
    pSetLayeredWindowAttributes=(SLWA)GetProcAddress(hmodUSER32,"SetLayeredWindowAttributes");   //함수포인터 얻음. 
    HWND hwnd = this->m_hWnd;                              //다이얼로그의 핸들 얻음. 
 
    SetWindowLong(hwnd, GWL_EXSTYLE,GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED); 
    pSetLayeredWindowAttributes(hwnd, 0, (255 * 70) / 100, LWA_ALPHA); 
 
    return TRUE;  // return TRUE  unless you set the focus to a control 

 
// 해당 다이알로그의 상단에 추가 
#define WS_EX_LAYERED           0x00080000 
#define LWA_COLORKEY            0x00000001 
#define LWA_ALPHA               0x00000002 
#define ULW_COLORKEY            0x00000001 
#define ULW_ALPHA               0x00000002 
#define ULW_OPAQUE              0x00000004 
  
typedef BOOL(WINAPI *SLWA)(HWND, COLORREF, BYTE, DWORD);

4 내 IP 얻는 방법
CString GetMyIPAddress() 

    char        chName[255]; 
    CString        sAddress; 
    PHOSTENT    pHostEntry; 
    IN_ADDR        inAddr; 
 
    if( gethostname( chName, 255 ) != 0 ) return ""; 
    else 
    { 
        if( ( pHostEntry = gethostbyname( chName ) ) == NULL ) return ""; 
        else 
        { 
            memcpy( &inAddr, pHostEntry->h_addr, 4 ); 
            sAddress.Format( "%s", inet_ntoa( inAddr ) ); 
            return sAddress; 
        } 
    } 
}

5 트레이 아이콘
void CWin1Dlg::OnButton1()  

            //일단 트레이아이콘 생성 
 
    NOTIFYICONDATA nid;     
                     
    nid.cbSize = sizeof(nid);  
    nid.hWnd = m_hWnd;         
    nid.uID = IDR_MAINFRAME;   
    nid.uFlags = NIF_MESSAGE|NIF_ICON|NIF_TIP; 
    nid.uCallbackMessage = WM_ICON_NOTIFY; 
    //이 부분이 중요 - 트레이 아이콘에서 이벤트 발생시 발생되는 메세지 정의하는 부분..  
    nid.hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);  
    strcpy(nid.szTip,"Test"); 
    Shell_NotifyIcon(NIM_ADD,&nid);  
    SendMessage(WM_SETICON,(WPARAM)TRUE,(LPARAM)nid.hIcon); 
 
    //일단 아이콘 생성하기 전에 다이얼로그를 숨겨야 겠죠..^^ 
    ShowWindow(SW_HIDE); 

 
void CWin1Dlg::OnButton2()  

    //다음 트레이아이콘 삭제 
    NOTIFYICONDATA nid; 
 
    nid.cbSize = sizeof(nid); 
    nid.hWnd = m_hWnd; 
    nid.uID = IDR_MAINFRAME; 
    Shell_NotifyIcon(NIM_DELETE,&nid); 
 
    //글구 이젠 다이얼로그를 나타나게.. 
    ShowWindow(SW_SHOW); 

 
LRESULT CWin1Dlg::OnTrayNotification(WPARAM wParam, LPARAM lParam) 

    // 왼쪽 마우스 버튼이 더블 클릭되었을 경우 
   if (LOWORD(lParam) == WM_LBUTTONDBLCLK)  
   { 
                // 프로그램 정보 다이얼로그 박스 출력 
                SendMessage(WM_COMMAND, IDC_BUTTON2); 
   } 
   return 1; 
}

6 패스 분리하는 방법
void _splitpath( const char *path, char *drive, char *dir, char *fname, char *ext ); 
를 쓰면 됩니다. 다음은 MSDN에 나와있는 예제입니다


#include  
#include  
 
void main( void ) 

   char path_buffer[_MAX_PATH]; 
   char drive[_MAX_DRIVE]; 
   char dir[_MAX_DIR]; 
   char fname[_MAX_FNAME]; 
   char ext[_MAX_EXT]; 
 
   _makepath( path_buffer, "c", "\\sample\\crt\\", "makepath", "c" ); 
  
   printf( "Path created with _makepath: %s\n\n", path_buffer ); 
  
   _splitpath( path_buffer, drive, dir, fname, ext ); 
  
   printf( "Path extracted with _splitpath:\n" ); 
   printf( "  Drive: %s\n", drive ); 
   printf( "  Dir: %s\n", dir ); 
   printf( "  Filename: %s\n", fname ); 
   printf( "  Ext: %s\n", ext ); 
}

7 FTP 관련
#include"CFTPTrans.h" 
 
CFTPTrans::CFTPTrans() 


 
CFTPTrans::~CFTPTrans() 

    DisConnect(); 

 
BOOL CFTPTrans::Connect(char *serverName, int port, char *username, char *password) 

    hInternet = InternetOpen("File Transfer for FTP", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); 
    if(hInternet == NULL) 
    { 
        errCode = GetLastError(); 
        return FALSE; 
    } 
  
    hFtpSession = InternetConnect(hInternet, serverName, port, username, password, INTERNET_SERVICE_FTP, INTERNET_FLAG_PASSIVE, 0); 
    if (NULL == hFtpSession) 
    { 
        InternetCloseHandle(hInternet); 
        errCode = GetLastError(); 
        return FALSE; 
    } 
    return TRUE; 

 
CFTPTrans::DisConnect() 

    InternetCloseHandle(hFtpSession);  
    InternetCloseHandle(hInternet); 

  
BOOL CFTPTrans::ChangeDirectroy(char *dirName) 

    if(!FtpSetCurrentDirectory(hFtpSession, dirName)) 
    { 
        errCode = GetLastError(); 
        return FALSE; 
    } 
    return TRUE; 

  
BOOL CFTPTrans::PutFile(char *source, char *destination) 

    if(!FtpPutFile(hFtpSession, source, destination, FTP_TRANSFER_TYPE_BINARY | INTERNET_FLAG_RELOAD, 0)) 
    { 
        errCode = GetLastError(); 
        return FALSE; 
    } 
    return TRUE; 
}

8 Downloaded Program Files 폴더의 OCX 삭제방법
typedef HRESULT (WINAPI *REMOVECONTROLBYNAME) 

             LPCTSTR lpszFile, 
             LPCTSTR lpszCLSID, 
             LPCTSTR lpszTypeLibID, 
             BOOL bForceRemove, 
             DWORD dwIsDistUnit 
); 
 
int _tmain(int argc, _TCHAR* argv[]) 

    HMODULE                   hMod; 
    REMOVECONTROLBYNAME       pfn =  NULL; 
 
    hMod = LoadLibrary("OCCACHE.DLL"); 
    if (hMod == NULL) 
    {   // Error loading module -- fail as securely as possible 
        return 0; 
    } 
 
    HRESULT hr; 
    pfn = (REMOVECONTROLBYNAME)GetProcAddress(hMod, "RemoveControlByName"); 
    if (pfn)  
    { 
        hr = (*pfn)(_T("C:\\WINDOWS\\Downloaded Program Files\\teechart5.ocx"), 
            _T("{B6C10532-FB89-11D4-93C9-006008A7EED4}"), 0, TRUE, TRUE); 
    } 
    FreeLibrary(hMod); 
 
    return 0; 

위에서 빨간 글자는 레지스트리에서 아래의 위치와 같습니다. 
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Code Store Database\Distribution Units 위 값의 하위키를 보면 숫자로된 키가 그것입니다. 
파란색 글자는 빨간색 숫자로된 키 밑에 '\Contains\Files' 로 들어가서 오른쪽 값을 참고하면됩니다.

 

9 디버깅 용도의 실행시간 출력 코드
디버깅시 TRACE로 시간정보를 출력하고 싶을때 사용한다.


#include <sys/timeb.h> 
 
void printCurrentTime() 

    time_t ltime; 
    struct _timeb tstruct; 
    struct tm *gmt; 
 
    time(<ime); 
    gmt = localtime(<ime); 
    _ftime( &tstruct ); 
    TRACE2("called - %u(ms) %s", tstruct.millitm, asctime(gmt)); 

예)


while(1) 

    Sleep(10); 
    printCurrentTime(); 

 
<실행결과> 
... 
called - 92(ms) Tue Oct 01 17:44:28 2002 
called - 102(ms) Tue Oct 01 17:44:28 2002 
...

10 Trace Tip
출처: http://www.codeproject.com/debug/tracetips.asp 
디버그 창에서 trace 메시지를 더블클릭하면 에디터 커서를 해당 라인으로 위치시킨다.


TRACE(_T("%s(%i) : Please double click on me!\n"), __FILE__,__LINE__);

11 모니터 끄기
PostMessage( GetDesktopWindow(),WM_SYSCOMMAND, SC_MONITORPOWER, 2 ); 

12 프로세스간 데이터 교환
보통 서로 다른 프로세스끼리 데이터를 주고 받을 때는 shared memory나 clipboard를 이용하는데 간단한 데이터를 주고 받을 때는 사용하기에 부담스러운 면이 있다. 이때 간편하게 이용할 수 있는 프로세스간 데이터 교환 방법을 이용한다.


1. GlobalAddAtom()을 이용한 데이터 전송 
예)


서버측: 
 
ATOM atom = GlobalAddAtom("This is test!");  
 
HWND hWnd = ::FindWindow(NULL, "AtomClinet");  
 
::PostMessage(hWnd, WM_MYMSG, 0, atom); // atom값을 전송  
 
클라언트측: 
void CATOMClientDlg::OnGetMsg(WPARAM wParam, LPARAM lParam)  
{  
    char vc_b[256];  
 
    ATOM atom = (ATOM)lParam;  
 
    GlobalGetAtomName(atom, vc_b, 256);  // vc_b를 사용  
}  
2. WM_COPYDATA를 이용한 데이터 교환


// source window에서..  
void CSourceWnd::Write(const void* lpBuf, UINT nCount)  
{  
       CWnd *pTraceWnd = CWnd::FindWindow(TRACEWND_CLASSNAME, NULL);  
 
       if (pTraceWnd) {  
              COPYDATASTRUCT cds;  
 
              cds.dwData = ID_COPYDATA_TRACEMSG /* Flag 용도 */;  
              cds.cbData = nCount;  
              cds.lpData = (void*)lpBuf;  
 
              pTraceWnd->SendMessage(WM_COPYDATA,  
                     (WPARAM)AfxGetApp()->m_pMainWnd->GetSafeHwnd(),  
                     (LPARAM)&cds);  
       } else {  
              AfxMessageBox("윈도우를 찾을 수 없습니다.");  
       }  
}  
 
//////////////////////////////////////////////////////  
// target windows에서..  
 
// 메세지 핸들링 설치  
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)  
       //{{AFX_MSG_MAP(CMainFrame)  
       ON_MESSAGE(WM_COPYDATA, OnTraceMsg)  
       .  
       .  
       .  
       //}}AFX_MSG_MAP  
 
END_MESSAGE_MAP()  
 
LRESULT CMainFrame::OnTraceMsg(WPARAM wParam, LPARAM lParam)  
{  
       COPYDATASTRUCT* pcds = (COPYDATASTRUCT*)lParam;  
 
       // pcds 를 사용한다..  
 
       return 0;  
}  
3. Shared section을 이용한 global variable 공유


#pragma data_seg("Shared") 
volatile LONG g_lSharedData = 0;   // initialized data 
#pragma data_seg() 
또는,


__declspec(allocate("Shared")) int g_nSharedData1 = 0;  // initialized data 
__declspec(allocate("Shared")) int g_nSharedData2;      // uninitialized data 
이때 dll의 프로세스간 데이타 공유라면 dll의 def파일에 데이타 공유 섹션을 지정해 줘야 한다.


SECTIONS 
        .Shared Read Write Shared 
이렇게 하면 g_lSharedData은 이 dll을 로딩한 모든 프로세스에서 공유해서 사용할 수 있다


4. File Map을 이용한 메모리 공유


// 
// 파일을 매핑하는 함수 
 
LPVOID InitFileMapping( HANDLE *phFileMap, char *pszShareName ) 
{      
     LPVOID lpMapView; 
 
     // 파일맵 핸들을 생성한다 
     *phFileMap = CreateFileMapping( (HANDLE)0xFFFFFFFF, NULL, PAGE_READWRITE, 
                              0, sizeof(DWORD), pszShareName ); 
     if( INVALID_HANDLE_VALUE == *phFileMap ) 
          return NULL; 
 
     // 파일을 매핑한다 
     lpMapView = MapViewOfFile( *phFileMap, FILE_MAP_ALL_ACCESS, 0, 0, 0 ); 
     if( NULL == lpMapView ) 
          return NULL; 
 
     // 매핑한 데이터의 선두번지를 리턴 
     return lpMapView; 

 
.... 
 
// 
// 파일맵 데이터를 쓰는 부분(1번 프로세스) 
pdwShare = (DWORD*)InitFileMapping( &hFileMap, dszFileMapName ); 
 
DWORD dwCount = 0; 
 
while( !( GetKeyState( VK_ESCAPE ) & 0x8000 ) ) 

     *pdwShare = ++dwCount; 
 
     printf( "Write - [%3d] %3d\n", dwCount, *pdwShare ); 
 
     Sleep( 500 ); 

 
... 
 
// 
// 파일맵 데이터를 읽는 부분(2번 프로세스) 
DWORD dwCount = 0; 
 
while( !( GetKeyState( VK_ESCAPE ) & 0x8000 ) ) 

     printf( "Read - [%3d] %3d\n", ++dwCount, *pdwShare ); 
 
     Sleep( 500 ); 

 
... 
 
// 파일매핑 해제 
UnmapViewOfFile( pdwShare ); 
CloseHandle( hFileMap );

13 Log 함수
윈도우 프로그래밍을 하다보면 가끔 dll 소스코드를 디버깅해야할 때가 있는데 이때 MSDEV의 디버거를 이용할수도 없기 때문에 디버깅하기가 까다롭다. 때론 printf대용인 MessageBox를 사용하기도 했는데 아무래도 썩 좋은 방법은 아니다. 이때 로그 함수를 만들어서 로그 파일을 생성하는 방법도 유용한 대안이다. 
아래는 Nasser Remy Rowhani라는 외국 친구가 쓴 코드인데 써보니 쓸만한 코드라 생각되서 소개한다. 굳이 디버깅 용도뿐만 아니라 API를 후킹하는 응용에서도 유용하게 쓸 수 있다.


#define LogFile "d:\\Logs\\LOG.txt"                   // log파일이 생성되는 위치 
#define Append(text) AppendLog(text, strlen(text))    // log를 기록하는 함수 
 
HANDLE   hLogFile=0;                // log파일의 핸들 
BOOL     IsLogging=false;           // log파일이 제대로 open되었는지 체크하는 플래그 
 
HANDLE OpenLog(char *Filename);     
BOOL CloseLog(HANDLE h=hLogFile);    
DWORD AppendLog(char *str, DWORD uSize, HANDLE h=hLogFile); 
 
HANDLE OpenLog(char *Filename) 

        HANDLE hLogFile; 
 
        hLogFile = CreateFile( Filename, GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_ALWAYS,0,0); 
        if(hLogFile!=INVALID_HANDLE_VALUE) 
                IsLogging = true;//SetFilePointer(hLogFile, 0,0, FILE_END);//*/ 
         
        return hLogFile; 

 
BOOL CloseLog(HANDLE h) 

        IsLogging = false; 
        return CloseHandle(h); 

 
DWORD AppendLog(char *str, DWORD uSize, HANDLE h) 

        DWORD written; 
        if(!IsLogging) return 0; 
 
        SetFilePointer( h, 0, 0, FILE_END ); 
        WriteFile(h, str, uSize, &written, 0); 
 
        return written; 

용례:


hLogFile = OpenLog( LogFile );   // 처음엔 log파일을 open한다. 
   ... 
sprintf(buf, "Error Code: %d", dwErr); 
Append(buf); 
   ... 
CloseLog();                     // 프로그램에서 exit할 때 log를 close

14 Ctrl+Esc, Alt+Tab, and Alt+Esc를 막는 법
출처: http://msdn.microsoft.com/msdnmag/issues/0700/win32


/************************************************************************ 
Module:  DisableLowLevelKeys.cpp 
Notices: Written 2000 Jeffrey Richter 
**************************************************************************/ 
 
#define _WIN32_WINNT 0x0400 
#include <Windows.h> 
 
LRESULT CALLBACK LowLevelKeyboardProc(int nCode,  
   WPARAM wParam, LPARAM lParam) { 
 
   BOOL fEatKeystroke = FALSE; 
 
   if (nCode == HC_ACTION) { 
      switch (wParam) { 
      case WM_KEYDOWN:  case WM_SYSKEYDOWN: 
      case WM_KEYUP:    case WM_SYSKEYUP:  
         PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT) lParam; 
         fEatKeystroke =  
            ((p->vkCode == VK_TAB) && ((p->flags & LLKHF_ALTDOWN) != 0)) || 
            ((p->vkCode == VK_ESCAPE) &&  
            ((p->flags & LLKHF_ALTDOWN) != 0)) || 
            ((p->vkCode == VK_ESCAPE) && ((GetKeyState(VK_CONTROL) &  
             0x8000) != 0)); 
         break; 
      } 
   } 
   return(fEatKeystroke ? 1 : CallNextHookEx(NULL, nCode, wParam,  
          lParam)); 

 
int WINAPI WinMain(HINSTANCE hinstExe, HINSTANCE, PTSTR pszCmdLine, int) { 
 
   // Install the low-level keyboard & mouse hooks 
   HHOOK hhkLowLevelKybd  = SetWindowsHookEx(WH_KEYBOARD_LL,  
      LowLevelKeyboardProc, hinstExe, 0); 
 
   // Keep this app running until we're told to stop 
   MessageBox(NULL,  
      TEXT("Alt+Esc, Ctrl+Esc, and Alt+Tab are now disabled.\n") 
      TEXT("Click \"Ok\" to terminate this application and re-enable 
            these keys."), 
      TEXT("Disable Low-Level Keys"), MB_OK); 
   UnhookWindowsHookEx(hhkLowLevelKybd); 
 
   return(0); 
}

15 About box에 URL 링크 걸기
About 대화상자에 웹으로 가는 링크를 넣는 방법. 이것은 액티브X 컨트롤을 이용하는 것이 가장 손쉬운 방법이다. IE에서 제공하는 오브젝트중 '마이크로소프트 웹브라우저'라는 것이 있는데 다음과 같이 하면 프로젝트에 포함된다.

 


1.Project 선택

2.Add to Project 선택

3.컴포넌트와 컨트롤 선택

4.Registered ActiveX Controls 폴더를 선택

5.Microsoft Web 브라우저라는 오브젝트 선택

6.컴포넌트 클래스 대화 상자에서 확인

7.대화상자 편집 모드에서 컨트롤 툴바에 등록된 웹브라우저 컨트롤을 대화상자에 드래그해 화면 디자인을 한다.

8.Class Wizard를 사용해서 Member Variable 탭에서 IDC_WEBxxx에 대한 데이터 멤버를 지정한다. 이때 Add Member Variable 대화상자의 category 콤보를 컨트롤로 지정

9.이제는 OnInitDialog등 원하는 지점에서 m_Webxxx로 지정된 멤버 객체 데이터를 사용해 다음과 같이 작성한다.

 m_WebBrowser.Navigate("http://dasomnetwork.com/~leedw", NULL, NULL, NULL, NULL); 
 위와 같이 해주면 대화상자가 기동 시에 동우의 홈페이지가 대화 상자에 나타날 것이다. 참고로 원격 사이트가 아닌 로컬에 html 문서를 미리 작성해서 가지고 있다가 URL 부분에 "file:///c:/My Documents/DHTML/ftv20/ftexample.html"라고 해주면 html이 나타난다.

 

16 특정 파일 오픈시 바로 프로그램 불러오기
ACDSee라는 그래픽 뷰어 프로그램같이 해당 그림 파일을 더블클릭하면 프로그램이 실행되면서 그 데이타를 불러오는 것과 같은 기능을 볼 수 있다. 이런 임의 파일의 싨행은 WinExec, ShellExecute API를 사용하면 구현할 수 있다. 여기서 원하는 것은 실행 파일 및 문서 파일들이므로 ShellExecute를 사용해야 한다.


HINSTANCE ShellExecute( 
    HWND hwnd,  
    LPCTSTR lpOperation, 
    LPCTSTR lpFile,  
    LPCTSTR lpParameters,  
    LPCTSTR lpDirectory, 
    INT nShowCmd 
);       
자세한 것은 MSDN 참조

 

17 드래그 앤 드롭으로 파일 오픈
윈도우 탐색기나 바탕 화면에서 드래그 앤 드롭으로 파일을 불러서 처리하고자 할 경우. 응용 프로그램에서의 드래그 앤 드롭의 처리는 InitInstance() 처리 부분에서 DragAcceptFiles라는 멤버 함수 또는 API를 수행하면 된다. 그러면 윈도우는 드래그 앤 드롭되는 것이 존재할 때 WM_DROP_FILES라는 메시지를 받는다.(이 메시지는 OnDropFiles(..)라는 멤버 함수가 처리한다.) 이 메시지에서 적당히 처리해주면 된다. 이것은 OLE와는 다른 것이니 주의한다.

 

18 app가 트레이에만 띄우도록 하려면
winamp같은 어플리케이션이 실행될 때 윈도우가 뜨더라도 상태바에는 뜨지 않고 트레이에만 생기는 모습을 보았을 것이다. 이것을 구현하려면 다음의 코드를 사용한다


void HideApplication(HWND hwnd) 

   ShowWindow(hwnd, SW_HIDE); 
   ShowOwnedPopups(hwnd, FALSE); 
    
   SetWindowPos(hwnd, HWND_BOTTOM, 0, 0, 0, 0, 
                 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); 

CApp 클래스에 위와 같은 이름을 가진 멤버 함수가 존재하는데 그 함수를 사용해도 된다. 실제 응용 프로그램을 태스크 바에서 사라지도록 하는 것은 SetWindowPos API에 있다. 또한 Shell_NotifyIcon이란 API가 있는데 이것을 이용해봐도 될 것이다.


WINSHELLAPI BOOL WINAPI Shell_NotifyIcon( 
    DWORD dwMessage,  
    PNOTIFYICONDATA pnid 
);       
주의해야할 것은 응용 프로그램은 메인 프레임을 가져야 하나 메인 프레임을 활성화시키지는 않도록 한다. 활성화만 안시키면 <Alt-Tab>에서 나타나지 않을 것이다. 대신 별도의 윈도우를 WS_POS으로 만들어 이를 트레이에 등록해야 한다. 즉, 트레이에 등록된 팝업 스타일의 윈도우가 모든 메시지를 가로채도록 하기 위함이다.

 

19 single thread 어플리케이션에 취소 버튼 구현
출처: http://www.fhcf.net/misc/id_ws/database/essays/fboyjoe/cancel/cancel.html


어플리케이션을 개발하다가 간혹 processor-intensive한 루틴을 작성해야할 때가 있다. 단일 쓰레드로 이를 구현했을 때는 하나의 루틴이 프로세서 자원을 다 잡아 먹기 때문에 윈도우즈 메시지를 처리할 수 없는 문제에 부딪힌다. 그래서 이때는 processor 자원을 많이 요구하는 연산 부분은 thread로 구현해서 돌려 놓고 원래의 thread는 윈도우 메시지를 처리하는 방법으로 구현을 한다. 그런데 별도의 쓰레드를 만들지 않고 단일 쓰레드에서 processor 자원 요구량이 많은 모듈과 윈도우즈 메시지를 동시에 처리할 수 있는 기법이 있어 소개한다.


결론을 미리 말하자면, processor-intensive한 연산 안에 message pump를 두어 메시지를 처리하도록 하며 유저가 언제든 취소를 원할 때 연산을 취소할 수 있도록 플래그를 검사하도록 하는 것이다. 플래그는 "취소"버튼을 눌렀을 경우에 셋팅되도록 한다. 핵심 부분을 코드로 살펴보면 다음과 같다.


void StartProcessing() 

   hCancelDialog = CreateDialog (inst, MAKEINTRESOURCE(IDD_DIALOG2),    
                               hwnd, CancelDialog); 
   ShowWindow (hCancelDialog, TRUE);          // 취소 버튼이 있는 대화 상자 출력 
   cancelled = 0;       // 취소 버튼이 눌렸는지에 대한 플래그 
    
   for ( ...) {       // 여기부터가 processor-intensive한 연산 부분이다. 
        .... 
    
        if(!MessagePump()) { // 연산 수행중에도 메시지를 처리할 수 있도록 한다. 
             return;       // WM_QUIT 메시지를 받으면 루틴을 빠져나간다. 
        }  
 
        if(cancelled) { 
            // 취소 플래그가 셋팅되면 연산을 중지한다. 
    
         .... 
    
   } 
   DestroyWindow(hCancelDialog); 
   EnableWindow(hwnd, TRUE); 
    
   .... 
 
BOOL MessagePump()        // 메시지 펌프 

   MSG msg; 
    
   while(PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {  // 메시지 큐에 메시지가 있는지 체크 
      if (!GetMessage(&msg, NULL, 0, 0)) {    // 메시지를 가져온다. 
         PostQuitMessage(0); 
         return FALSE; 
      } 
      TranslateMessage(&msg); 
      DispatchMessage(&msg); 
   } 
   return TRUE; 

예제 프로젝트 : CancelTestApp.zip

 

20 PC시간 셋팅하기
void CSetDateDlg::OnOK()  

        // TODO: Add extra validation here 
 
        CTime time( 2005, 1, 10, 22, 17, 43 );  
        SYSTEMTIME sysTime; 
 
        time.GetAsSystemTime(sysTime); 
 
        if (getSystemType() == VER_PLATFORM_WIN32_NT) 
        { // NT 계열이면 시간을 바꿀 수 있는 특권을 가져와야 한다. 
                HANDLE hToken; 
                TOKEN_PRIVILEGES tp; 
                LUID luid; 
 
                OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken); 
                LookupPrivilegeValue(NULL, "SeSystemtimePrivilege", &luid); 
 
                tp.PrivilegeCount = 1; 
                tp.Privileges[0].Luid = luid; 
                tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 
                AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL); 
        } 
 
        SetLocalTime(&sysTime); 
         
        CDialog::OnOK(); 

 
void CSetDateDlg::getSystemType() 

        OSVERSIONINFO osv; 
 
        osv.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); 
        GetVersionEx(&osv); 
 
        return osv.dwPlatformId; 
}

 


출처: http://www.dasomnetwork.com/~leedw/mywiki/moin.cgi/win32_2f_c4_da_b5_e5_c6_c1?action=highlight&value=VisualC%2B%2B%C6%C1%C1%F6%B5%B5 

Posted by SB패밀리

Visual C++에 관련된 유용한 코드 팁
내용


1.Link: Knowledge Base
2.다이알로그에 스킨 입히기
3.투명 윈도우 만들기
4.내 IP 얻는 방법
5.트레이 아이콘
6.패스 분리하는 방법
7.FTP 관련
8.Downloaded Program Files 폴더의 OCX 삭제방법
9.디버깅 용도의 실행시간 출력 코드
10.Trace Tip
11.모니터 끄기
12.프로세스간 데이터 교환
13.Log 함수
14.Ctrl+Esc, Alt+Tab, and Alt+Esc를 막는 법
15.About box에 URL 링크 걸기
16.특정 파일 오픈시 바로 프로그램 불러오기
17.드래그 앤 드롭으로 파일 오픈
18.app가 트레이에만 띄우도록 하려면
19.single thread 어플리케이션에 취소 버튼 구현
20.PC시간 셋팅하기
1 Link: Knowledge Base
Knowledge base : MFC 및 Visual C++ 프로그래밍에 대한 방대한 tip과 know-how를 담고 있다.

 

2 다이알로그에 스킨 입히기
void CDlgPictureDlg::OnPaint() 
{
    if (IsIconic())
    {
        CPaintDC dc(this); // device context for painting
 
        SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
 
        // Center icon in client rectangle
        int cxIcon = GetSystemMetrics(SM_CXICON);
        int cyIcon = GetSystemMetrics(SM_CYICON);
        CRect rect;
        GetClientRect(&rect);
        int x = (rect.Width() - cxIcon + 1) / 2;
        int y = (rect.Height() - cyIcon + 1) / 2;
 
        // Draw the icon
        dc.DrawIcon(x, y, m_hIcon);
    }
    else
    {    
        CWindowDC dc(this);
        CDC memDC;
        memDC.CreateCompatibleDC(&dc);
        CBitmap bitmap;
        BITMAP bm;
        bitmap.LoadBitmap(IDB_BITMAP1);      <<-- 비트맵 이미지를 만들어야한다.
        bitmap.GetBitmap(&bm);
        CBitmap* pOld = memDC.SelectObject(&bitmap);
        dc.BitBlt(5, 30, bm.bmWidth, bm.bmHeight, &memDC, 0, 0, SRCCOPY);
        dc.SelectObject(pOld);
        memDC.DeleteDC();
        CDialog::OnPaint();
    }
 
}
3 투명 윈도우 만들기
BOOL CWin1Dlg::OnInitDialog()
{
    CDialog::OnInitDialog();
 
    SLWA pSetLayeredWindowAttributes = NULL;     // 함수포인터 선언, 초기화.
    HINSTANCE hmodUSER32 = LoadLibrary("USER32.DLL");  // 인스턴스 얻음.
    pSetLayeredWindowAttributes=(SLWA)GetProcAddress(hmodUSER32,"SetLayeredWindowAttributes");   //함수포인터 얻음.
    HWND hwnd = this->m_hWnd;                              //다이얼로그의 핸들 얻음.
 
    SetWindowLong(hwnd, GWL_EXSTYLE,GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);
    pSetLayeredWindowAttributes(hwnd, 0, (255 * 70) / 100, LWA_ALPHA);
 
    return TRUE;  // return TRUE  unless you set the focus to a control
}
 
// 해당 다이알로그의 상단에 추가
#define WS_EX_LAYERED           0x00080000
#define LWA_COLORKEY            0x00000001
#define LWA_ALPHA               0x00000002
#define ULW_COLORKEY            0x00000001
#define ULW_ALPHA               0x00000002
#define ULW_OPAQUE              0x00000004
 
typedef BOOL(WINAPI *SLWA)(HWND, COLORREF, BYTE, DWORD);

4 내 IP 얻는 방법
CString GetMyIPAddress()
{
    char        chName[255];
    CString        sAddress;
    PHOSTENT    pHostEntry;
    IN_ADDR        inAddr;
 
    if( gethostname( chName, 255 ) != 0 ) return "";
    else
    {
        if( ( pHostEntry = gethostbyname( chName ) ) == NULL ) return "";
        else
        {
            memcpy( &inAddr, pHostEntry->h_addr, 4 );
            sAddress.Format( "%s", inet_ntoa( inAddr ) );
            return sAddress;
        }
    }
}

5 트레이 아이콘
void CWin1Dlg::OnButton1() 
{
            //일단 트레이아이콘 생성
 
    NOTIFYICONDATA nid;    
                    
    nid.cbSize = sizeof(nid); 
    nid.hWnd = m_hWnd;        
    nid.uID = IDR_MAINFRAME;  
    nid.uFlags = NIF_MESSAGE|NIF_ICON|NIF_TIP;
    nid.uCallbackMessage = WM_ICON_NOTIFY;
    //이 부분이 중요 - 트레이 아이콘에서 이벤트 발생시 발생되는 메세지 정의하는 부분.. 
    nid.hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); 
    strcpy(nid.szTip,"Test");
    Shell_NotifyIcon(NIM_ADD,&nid); 
    SendMessage(WM_SETICON,(WPARAM)TRUE,(LPARAM)nid.hIcon);
 
    //일단 아이콘 생성하기 전에 다이얼로그를 숨겨야 겠죠..^^
    ShowWindow(SW_HIDE);
}
 
void CWin1Dlg::OnButton2() 
{
    //다음 트레이아이콘 삭제
    NOTIFYICONDATA nid;
 
    nid.cbSize = sizeof(nid);
    nid.hWnd = m_hWnd;
    nid.uID = IDR_MAINFRAME;
    Shell_NotifyIcon(NIM_DELETE,&nid);
 
    //글구 이젠 다이얼로그를 나타나게..
    ShowWindow(SW_SHOW);
}
 
LRESULT CWin1Dlg::OnTrayNotification(WPARAM wParam, LPARAM lParam)
{
    // 왼쪽 마우스 버튼이 더블 클릭되었을 경우
   if (LOWORD(lParam) == WM_LBUTTONDBLCLK) 
   {
                // 프로그램 정보 다이얼로그 박스 출력
                SendMessage(WM_COMMAND, IDC_BUTTON2);
   }
   return 1;
}

6 패스 분리하는 방법
void _splitpath( const char *path, char *drive, char *dir, char *fname, char *ext );
를 쓰면 됩니다. 다음은 MSDN에 나와있는 예제입니다


#include 
#include 
 
void main( void )
{
   char path_buffer[_MAX_PATH];
   char drive[_MAX_DRIVE];
   char dir[_MAX_DIR];
   char fname[_MAX_FNAME];
   char ext[_MAX_EXT];
 
   _makepath( path_buffer, "c", "\\sample\\crt\\", "makepath", "c" );
 
   printf( "Path created with _makepath: %s\n\n", path_buffer );
 
   _splitpath( path_buffer, drive, dir, fname, ext );
 
   printf( "Path extracted with _splitpath:\n" );
   printf( "  Drive: %s\n", drive );
   printf( "  Dir: %s\n", dir );
   printf( "  Filename: %s\n", fname );
   printf( "  Ext: %s\n", ext );
}

7 FTP 관련
#include"CFTPTrans.h"
 
CFTPTrans::CFTPTrans()
{
}
 
CFTPTrans::~CFTPTrans()
{
    DisConnect();
}
 
BOOL CFTPTrans::Connect(char *serverName, int port, char *username, char *password)
{
    hInternet = InternetOpen("File Transfer for FTP", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
    if(hInternet == NULL)
    {
        errCode = GetLastError();
        return FALSE;
    }
 
    hFtpSession = InternetConnect(hInternet, serverName, port, username, password, INTERNET_SERVICE_FTP, INTERNET_FLAG_PASSIVE, 0);
    if (NULL == hFtpSession)
    {
        InternetCloseHandle(hInternet);
        errCode = GetLastError();
        return FALSE;
    }
    return TRUE;
}
 
CFTPTrans::DisConnect()
{
    InternetCloseHandle(hFtpSession); 
    InternetCloseHandle(hInternet);
}
 
BOOL CFTPTrans::ChangeDirectroy(char *dirName)
{
    if(!FtpSetCurrentDirectory(hFtpSession, dirName))
    {
        errCode = GetLastError();
        return FALSE;
    }
    return TRUE;
}
 
BOOL CFTPTrans::PutFile(char *source, char *destination)
{
    if(!FtpPutFile(hFtpSession, source, destination, FTP_TRANSFER_TYPE_BINARY | INTERNET_FLAG_RELOAD, 0))
    {
        errCode = GetLastError();
        return FALSE;
    }
    return TRUE;
}

8 Downloaded Program Files 폴더의 OCX 삭제방법
typedef HRESULT (WINAPI *REMOVECONTROLBYNAME)
(
             LPCTSTR lpszFile,
             LPCTSTR lpszCLSID,
             LPCTSTR lpszTypeLibID,
             BOOL bForceRemove,
             DWORD dwIsDistUnit
);
 
int _tmain(int argc, _TCHAR* argv[])
{
    HMODULE                   hMod;
    REMOVECONTROLBYNAME       pfn =  NULL;
 
    hMod = LoadLibrary("OCCACHE.DLL");
    if (hMod == NULL)
    {   // Error loading module -- fail as securely as possible
        return 0;
    }
 
    HRESULT hr;
    pfn = (REMOVECONTROLBYNAME)GetProcAddress(hMod, "RemoveControlByName");
    if (pfn) 
    {
        hr = (*pfn)(_T("C:\\WINDOWS\\Downloaded Program Files\\teechart5.ocx"),
            _T("{B6C10532-FB89-11D4-93C9-006008A7EED4}"), 0, TRUE, TRUE);
    }
    FreeLibrary(hMod);
 
    return 0;
}
위에서 빨간 글자는 레지스트리에서 아래의 위치와 같습니다.
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Code Store Database\Distribution Units 위 값의 하위키를 보면 숫자로된 키가 그것입니다.
파란색 글자는 빨간색 숫자로된 키 밑에 '\Contains\Files' 로 들어가서 오른쪽 값을 참고하면됩니다.

 

9 디버깅 용도의 실행시간 출력 코드
디버깅시 TRACE로 시간정보를 출력하고 싶을때 사용한다.


#include <sys/timeb.h>
 
void printCurrentTime()
{
    time_t ltime;
    struct _timeb tstruct;
    struct tm *gmt;
 
    time(<ime);
    gmt = localtime(<ime);
    _ftime( &tstruct );
    TRACE2("called - %u(ms) %s", tstruct.millitm, asctime(gmt));
}
예)


while(1)
{
    Sleep(10);
    printCurrentTime();
}
 
<실행결과>
...
called - 92(ms) Tue Oct 01 17:44:28 2002
called - 102(ms) Tue Oct 01 17:44:28 2002
...

10 Trace Tip
출처: http://www.codeproject.com/debug/tracetips.asp
디버그 창에서 trace 메시지를 더블클릭하면 에디터 커서를 해당 라인으로 위치시킨다.


TRACE(_T("%s(%i) : Please double click on me!\n"), __FILE__,__LINE__);

11 모니터 끄기
PostMessage( GetDesktopWindow(),WM_SYSCOMMAND, SC_MONITORPOWER, 2 ); 

12 프로세스간 데이터 교환
보통 서로 다른 프로세스끼리 데이터를 주고 받을 때는 shared memory나 clipboard를 이용하는데 간단한 데이터를 주고 받을 때는 사용하기에 부담스러운 면이 있다. 이때 간편하게 이용할 수 있는 프로세스간 데이터 교환 방법을 이용한다.


1. GlobalAddAtom()을 이용한 데이터 전송
예)


서버측:
 
ATOM atom = GlobalAddAtom("This is test!"); 
 
HWND hWnd = ::FindWindow(NULL, "AtomClinet"); 
 
::PostMessage(hWnd, WM_MYMSG, 0, atom); // atom값을 전송 
 
클라언트측:
void CATOMClientDlg::OnGetMsg(WPARAM wParam, LPARAM lParam) 

    char vc_b[256]; 
 
    ATOM atom = (ATOM)lParam; 
 
    GlobalGetAtomName(atom, vc_b, 256);  // vc_b를 사용 

2. WM_COPYDATA를 이용한 데이터 교환


// source window에서.. 
void CSourceWnd::Write(const void* lpBuf, UINT nCount) 

       CWnd *pTraceWnd = CWnd::FindWindow(TRACEWND_CLASSNAME, NULL); 
 
       if (pTraceWnd) { 
              COPYDATASTRUCT cds; 
 
              cds.dwData = ID_COPYDATA_TRACEMSG /* Flag 용도 */; 
              cds.cbData = nCount; 
              cds.lpData = (void*)lpBuf; 
 
              pTraceWnd->SendMessage(WM_COPYDATA, 
                     (WPARAM)AfxGetApp()->m_pMainWnd->GetSafeHwnd(), 
                     (LPARAM)&cds); 
       } else { 
              AfxMessageBox("윈도우를 찾을 수 없습니다."); 
       } 

 
////////////////////////////////////////////////////// 
// target windows에서.. 
 
// 메세지 핸들링 설치 
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) 
       //{{AFX_MSG_MAP(CMainFrame) 
       ON_MESSAGE(WM_COPYDATA, OnTraceMsg) 
       . 
       . 
       . 
       //}}AFX_MSG_MAP 
 
END_MESSAGE_MAP() 
 
LRESULT CMainFrame::OnTraceMsg(WPARAM wParam, LPARAM lParam) 

       COPYDATASTRUCT* pcds = (COPYDATASTRUCT*)lParam; 
 
       // pcds 를 사용한다.. 
 
       return 0; 

3. Shared section을 이용한 global variable 공유


#pragma data_seg("Shared")
volatile LONG g_lSharedData = 0;   // initialized data
#pragma data_seg()
또는,


__declspec(allocate("Shared")) int g_nSharedData1 = 0;  // initialized data
__declspec(allocate("Shared")) int g_nSharedData2;      // uninitialized data
이때 dll의 프로세스간 데이타 공유라면 dll의 def파일에 데이타 공유 섹션을 지정해 줘야 한다.


SECTIONS
        .Shared Read Write Shared
이렇게 하면 g_lSharedData은 이 dll을 로딩한 모든 프로세스에서 공유해서 사용할 수 있다


4. File Map을 이용한 메모리 공유


//
// 파일을 매핑하는 함수
 
LPVOID InitFileMapping( HANDLE *phFileMap, char *pszShareName )
{     
     LPVOID lpMapView;
 
     // 파일맵 핸들을 생성한다
     *phFileMap = CreateFileMapping( (HANDLE)0xFFFFFFFF, NULL, PAGE_READWRITE,
                              0, sizeof(DWORD), pszShareName );
     if( INVALID_HANDLE_VALUE == *phFileMap )
          return NULL;
 
     // 파일을 매핑한다
     lpMapView = MapViewOfFile( *phFileMap, FILE_MAP_ALL_ACCESS, 0, 0, 0 );
     if( NULL == lpMapView )
          return NULL;
 
     // 매핑한 데이터의 선두번지를 리턴
     return lpMapView;
}
 
....
 
//
// 파일맵 데이터를 쓰는 부분(1번 프로세스)
pdwShare = (DWORD*)InitFileMapping( &hFileMap, dszFileMapName );
 
DWORD dwCount = 0;
 
while( !( GetKeyState( VK_ESCAPE ) & 0x8000 ) )
{
     *pdwShare = ++dwCount;
 
     printf( "Write - [%3d] %3d\n", dwCount, *pdwShare );
 
     Sleep( 500 );
}
 
...
 
//
// 파일맵 데이터를 읽는 부분(2번 프로세스)
DWORD dwCount = 0;
 
while( !( GetKeyState( VK_ESCAPE ) & 0x8000 ) )
{
     printf( "Read - [%3d] %3d\n", ++dwCount, *pdwShare );
 
     Sleep( 500 );
}
 
...
 
// 파일매핑 해제
UnmapViewOfFile( pdwShare );
CloseHandle( hFileMap );

13 Log 함수
윈도우 프로그래밍을 하다보면 가끔 dll 소스코드를 디버깅해야할 때가 있는데 이때 MSDEV의 디버거를 이용할수도 없기 때문에 디버깅하기가 까다롭다. 때론 printf대용인 MessageBox를 사용하기도 했는데 아무래도 썩 좋은 방법은 아니다. 이때 로그 함수를 만들어서 로그 파일을 생성하는 방법도 유용한 대안이다.
아래는 Nasser Remy Rowhani라는 외국 친구가 쓴 코드인데 써보니 쓸만한 코드라 생각되서 소개한다. 굳이 디버깅 용도뿐만 아니라 API를 후킹하는 응용에서도 유용하게 쓸 수 있다.


#define LogFile "d:\\Logs\\LOG.txt"                   // log파일이 생성되는 위치
#define Append(text) AppendLog(text, strlen(text))    // log를 기록하는 함수
 
HANDLE   hLogFile=0;                // log파일의 핸들
BOOL     IsLogging=false;           // log파일이 제대로 open되었는지 체크하는 플래그
 
HANDLE OpenLog(char *Filename);    
BOOL CloseLog(HANDLE h=hLogFile);   
DWORD AppendLog(char *str, DWORD uSize, HANDLE h=hLogFile);
 
HANDLE OpenLog(char *Filename)
{
        HANDLE hLogFile;
 
        hLogFile = CreateFile( Filename, GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_ALWAYS,0,0);
        if(hLogFile!=INVALID_HANDLE_VALUE)
                IsLogging = true;//SetFilePointer(hLogFile, 0,0, FILE_END);//*/
        
        return hLogFile;
}
 
BOOL CloseLog(HANDLE h)
{
        IsLogging = false;
        return CloseHandle(h);
}
 
DWORD AppendLog(char *str, DWORD uSize, HANDLE h)
{
        DWORD written;
        if(!IsLogging) return 0;
 
        SetFilePointer( h, 0, 0, FILE_END );
        WriteFile(h, str, uSize, &written, 0);
 
        return written;
}
용례:


hLogFile = OpenLog( LogFile );   // 처음엔 log파일을 open한다.
   ...
sprintf(buf, "Error Code: %d", dwErr);
Append(buf);
   ...
CloseLog();                     // 프로그램에서 exit할 때 log를 close

14 Ctrl+Esc, Alt+Tab, and Alt+Esc를 막는 법
출처: http://msdn.microsoft.com/msdnmag/issues/0700/win32


/************************************************************************
Module:  DisableLowLevelKeys.cpp
Notices: Written 2000 Jeffrey Richter
**************************************************************************/
 
#define _WIN32_WINNT 0x0400
#include <Windows.h>
 
LRESULT CALLBACK LowLevelKeyboardProc(int nCode, 
   WPARAM wParam, LPARAM lParam) {
 
   BOOL fEatKeystroke = FALSE;
 
   if (nCode == HC_ACTION) {
      switch (wParam) {
      case WM_KEYDOWN:  case WM_SYSKEYDOWN:
      case WM_KEYUP:    case WM_SYSKEYUP: 
         PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT) lParam;
         fEatKeystroke = 
            ((p->vkCode == VK_TAB) && ((p->flags & LLKHF_ALTDOWN) != 0)) ||
            ((p->vkCode == VK_ESCAPE) && 
            ((p->flags & LLKHF_ALTDOWN) != 0)) ||
            ((p->vkCode == VK_ESCAPE) && ((GetKeyState(VK_CONTROL) & 
             0x8000) != 0));
         break;
      }
   }
   return(fEatKeystroke ? 1 : CallNextHookEx(NULL, nCode, wParam, 
          lParam));
}
 
int WINAPI WinMain(HINSTANCE hinstExe, HINSTANCE, PTSTR pszCmdLine, int) {
 
   // Install the low-level keyboard & mouse hooks
   HHOOK hhkLowLevelKybd  = SetWindowsHookEx(WH_KEYBOARD_LL, 
      LowLevelKeyboardProc, hinstExe, 0);
 
   // Keep this app running until we're told to stop
   MessageBox(NULL, 
      TEXT("Alt+Esc, Ctrl+Esc, and Alt+Tab are now disabled.\n")
      TEXT("Click \"Ok\" to terminate this application and re-enable
            these keys."),
      TEXT("Disable Low-Level Keys"), MB_OK);
   UnhookWindowsHookEx(hhkLowLevelKybd);
 
   return(0);
}

15 About box에 URL 링크 걸기
About 대화상자에 웹으로 가는 링크를 넣는 방법. 이것은 액티브X 컨트롤을 이용하는 것이 가장 손쉬운 방법이다. IE에서 제공하는 오브젝트중 '마이크로소프트 웹브라우저'라는 것이 있는데 다음과 같이 하면 프로젝트에 포함된다.

 


1.Project 선택

2.Add to Project 선택

3.컴포넌트와 컨트롤 선택

4.Registered ActiveX Controls 폴더를 선택

5.Microsoft Web 브라우저라는 오브젝트 선택

6.컴포넌트 클래스 대화 상자에서 확인

7.대화상자 편집 모드에서 컨트롤 툴바에 등록된 웹브라우저 컨트롤을 대화상자에 드래그해 화면 디자인을 한다.

8.Class Wizard를 사용해서 Member Variable 탭에서 IDC_WEBxxx에 대한 데이터 멤버를 지정한다. 이때 Add Member Variable 대화상자의 category 콤보를 컨트롤로 지정

9.이제는 OnInitDialog등 원하는 지점에서 m_Webxxx로 지정된 멤버 객체 데이터를 사용해 다음과 같이 작성한다.

 m_WebBrowser.Navigate("http://dasomnetwork.com/~leedw", NULL, NULL, NULL, NULL);
 위와 같이 해주면 대화상자가 기동 시에 동우의 홈페이지가 대화 상자에 나타날 것이다. 참고로 원격 사이트가 아닌 로컬에 html 문서를 미리 작성해서 가지고 있다가 URL 부분에 "file:///c:/My Documents/DHTML/ftv20/ftexample.html"라고 해주면 html이 나타난다.

 

16 특정 파일 오픈시 바로 프로그램 불러오기
ACDSee라는 그래픽 뷰어 프로그램같이 해당 그림 파일을 더블클릭하면 프로그램이 실행되면서 그 데이타를 불러오는 것과 같은 기능을 볼 수 있다. 이런 임의 파일의 싨행은 WinExec, ShellExecute API를 사용하면 구현할 수 있다. 여기서 원하는 것은 실행 파일 및 문서 파일들이므로 ShellExecute를 사용해야 한다.


HINSTANCE ShellExecute(
    HWND hwnd, 
    LPCTSTR lpOperation,
    LPCTSTR lpFile, 
    LPCTSTR lpParameters, 
    LPCTSTR lpDirectory,
    INT nShowCmd
);      
자세한 것은 MSDN 참조

 

17 드래그 앤 드롭으로 파일 오픈
윈도우 탐색기나 바탕 화면에서 드래그 앤 드롭으로 파일을 불러서 처리하고자 할 경우. 응용 프로그램에서의 드래그 앤 드롭의 처리는 InitInstance() 처리 부분에서 DragAcceptFiles라는 멤버 함수 또는 API를 수행하면 된다. 그러면 윈도우는 드래그 앤 드롭되는 것이 존재할 때 WM_DROP_FILES라는 메시지를 받는다.(이 메시지는 OnDropFiles(..)라는 멤버 함수가 처리한다.) 이 메시지에서 적당히 처리해주면 된다. 이것은 OLE와는 다른 것이니 주의한다.

 

18 app가 트레이에만 띄우도록 하려면
winamp같은 어플리케이션이 실행될 때 윈도우가 뜨더라도 상태바에는 뜨지 않고 트레이에만 생기는 모습을 보았을 것이다. 이것을 구현하려면 다음의 코드를 사용한다


void HideApplication(HWND hwnd)
{
   ShowWindow(hwnd, SW_HIDE);
   ShowOwnedPopups(hwnd, FALSE);
   
   SetWindowPos(hwnd, HWND_BOTTOM, 0, 0, 0, 0,
                 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
}
CApp 클래스에 위와 같은 이름을 가진 멤버 함수가 존재하는데 그 함수를 사용해도 된다. 실제 응용 프로그램을 태스크 바에서 사라지도록 하는 것은 SetWindowPos API에 있다. 또한 Shell_NotifyIcon이란 API가 있는데 이것을 이용해봐도 될 것이다.


WINSHELLAPI BOOL WINAPI Shell_NotifyIcon(
    DWORD dwMessage, 
    PNOTIFYICONDATA pnid
);      
주의해야할 것은 응용 프로그램은 메인 프레임을 가져야 하나 메인 프레임을 활성화시키지는 않도록 한다. 활성화만 안시키면 <Alt-Tab>에서 나타나지 않을 것이다. 대신 별도의 윈도우를 WS_POS으로 만들어 이를 트레이에 등록해야 한다. 즉, 트레이에 등록된 팝업 스타일의 윈도우가 모든 메시지를 가로채도록 하기 위함이다.

 

19 single thread 어플리케이션에 취소 버튼 구현
출처: http://www.fhcf.net/misc/id_ws/database/essays/fboyjoe/cancel/cancel.html


어플리케이션을 개발하다가 간혹 processor-intensive한 루틴을 작성해야할 때가 있다. 단일 쓰레드로 이를 구현했을 때는 하나의 루틴이 프로세서 자원을 다 잡아 먹기 때문에 윈도우즈 메시지를 처리할 수 없는 문제에 부딪힌다. 그래서 이때는 processor 자원을 많이 요구하는 연산 부분은 thread로 구현해서 돌려 놓고 원래의 thread는 윈도우 메시지를 처리하는 방법으로 구현을 한다. 그런데 별도의 쓰레드를 만들지 않고 단일 쓰레드에서 processor 자원 요구량이 많은 모듈과 윈도우즈 메시지를 동시에 처리할 수 있는 기법이 있어 소개한다.


결론을 미리 말하자면, processor-intensive한 연산 안에 message pump를 두어 메시지를 처리하도록 하며 유저가 언제든 취소를 원할 때 연산을 취소할 수 있도록 플래그를 검사하도록 하는 것이다. 플래그는 "취소"버튼을 눌렀을 경우에 셋팅되도록 한다. 핵심 부분을 코드로 살펴보면 다음과 같다.


void StartProcessing()
{
   hCancelDialog = CreateDialog (inst, MAKEINTRESOURCE(IDD_DIALOG2),   
                               hwnd, CancelDialog);
   ShowWindow (hCancelDialog, TRUE);          // 취소 버튼이 있는 대화 상자 출력
   cancelled = 0;       // 취소 버튼이 눌렸는지에 대한 플래그
   
   for ( ...) {       // 여기부터가 processor-intensive한 연산 부분이다.
        ....
   
        if(!MessagePump()) { // 연산 수행중에도 메시지를 처리할 수 있도록 한다.
             return;       // WM_QUIT 메시지를 받으면 루틴을 빠져나간다.
        } 
 
        if(cancelled) {
            // 취소 플래그가 셋팅되면 연산을 중지한다.
   
         ....
   
   }
   DestroyWindow(hCancelDialog);
   EnableWindow(hwnd, TRUE);
   
   ....
 
BOOL MessagePump()        // 메시지 펌프
{
   MSG msg;
   
   while(PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {  // 메시지 큐에 메시지가 있는지 체크
      if (!GetMessage(&msg, NULL, 0, 0)) {    // 메시지를 가져온다.
         PostQuitMessage(0);
         return FALSE;
      }
      TranslateMessage(&msg);
      DispatchMessage(&msg);
   }
   return TRUE;
}
예제 프로젝트 : CancelTestApp.zip

 

20 PC시간 셋팅하기
void CSetDateDlg::OnOK() 
{
        // TODO: Add extra validation here
 
        CTime time( 2005, 1, 10, 22, 17, 43 ); 
        SYSTEMTIME sysTime;
 
        time.GetAsSystemTime(sysTime);
 
        if (getSystemType() == VER_PLATFORM_WIN32_NT)
        { // NT 계열이면 시간을 바꿀 수 있는 특권을 가져와야 한다.
                HANDLE hToken;
                TOKEN_PRIVILEGES tp;
                LUID luid;
 
                OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
                LookupPrivilegeValue(NULL, "SeSystemtimePrivilege", &luid);
 
                tp.PrivilegeCount = 1;
                tp.Privileges[0].Luid = luid;
                tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
                AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL);
        }
 
        SetLocalTime(&sysTime);
        
        CDialog::OnOK();
}
 
void CSetDateDlg::getSystemType()
{
        OSVERSIONINFO osv;
 
        osv.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
        GetVersionEx(&osv);
 
        return osv.dwPlatformId;
}

 


출처: http://www.dasomnetwork.com/~leedw/mywiki/moin.cgi/win32_2f_c4_da_b5_e5_c6_c1?action=highlight&value=VisualC%2B%2B%C6%C1%C1%F6%B5%B5

Posted by SB패밀리


ANSI 또는 유니코드 컨트롤 버전

컨트롤을 ANSI 버전으로 제공할지 유니코드 버전으로 제공할지 또는 두 버전을 모두 제공할지 여부를 결정해야 합니다. 이러한 사항은 ANSI 및 유니코드 문자 집합 고유의 이식성과 관련된 요소에 따라 결정됩니다.

모든 Win32 운영 체제에서 작동하는 ANSI 컨트롤을 사용하면 다양한 Win32 운영 체제 간의 이식성을 최대화할 수 있습니다. 반면, 유니코드 컨트롤은 Windows NT(버전 3.51 이상)에서만 작동하고 Windows 95나 Windows 98에서는 작동하지 않습니다. 따라서 이식성 문제가 주요 관심사인 경우에는 ANSI 컨트롤을 제공해야 합니다. Windows NT에서만 컨트롤을 실행할 계획인 경우에는 유니코드 컨트롤을 제공할 수 있습니다. 또한 두 가지 버전을 모두 제공하여 해당 응용 프로그램에서 사용자의 운영 체제에 따라 가장 적절한 버전을 설치하도록 할 수도 있습니다.

ActiveX 컨트롤 및 재배포 가능한 DLL 설치

ActiveX 컨트롤과 함께 제공되는 설치 프로그램을 통해 Windows 디렉터리에 별도의 하위 디렉터리를 만들고 이 하위 디렉터리에 해당 컨트롤의 .OCX 파일이 설치되도록 해야 합니다.

참고   설치 프로그램에 Windows GetWindowsDirectory API를 사용하면 Windows 디렉터리의 이름을 가져올 수 있습니다. 또한 사용자의 회사 또는 제품 이름을 사용하여 하위 디렉터리 이름을 만들 수도 있습니다.
설치 프로그램을 통해 Windows 시스템 디렉터리에 재배포 가능한 필수 DLL 파일이 설치되어야 합니다. 또한 사용자의 시스템에 필수 DLL 중 하나라도 이미 설치되어 있는 경우, 설치 프로그램에서 해당 DLL의 버전과 설치하려는 DLL의 버전을 비교한 후 이미 설치된 파일보다 설치하려는 파일의 버전 번호가 더 높은 경우에만 해당 파일을 다시 설치하도록 해야 합니다.

ActiveX 컨트롤은 OLE 컨테이너 응용 프로그램 내에서만 사용할 수 있으므로 모든 OLE DLL을 컨트롤과 함께 배포하지 않아도 됩니다. 이것이 가능한 이유는 포함하는 응용 프로그램이나 운영 체제 자체에 표준 OLE DLL이 설치되어 있기 때문입니다.

컨트롤 등록

컨트롤을 사용하려면 먼저 Windows 등록 데이터베이스에 해당 컨트롤에 대한 적절한 엔트리를 만들어야 합니다. 일부 ActiveX 컨트롤 컨테이너는 사용자가 새 컨트롤을 등록할 수 있도록 메뉴 항목을 제공하지만 모든 컨테이너에서 이 기능을 사용할 수 있는 것은 아닙니다. 따라서 컨트롤 설치 시 설치 프로그램에서 해당 컨트롤을 등록하도록 만들 수 있습니다. 이 경우, Visual C++에는 컨트롤을 등록하는 데 사용할 수 있는 RegSvr32.exe라는 재배포 가능한 프로그램이 포함되어 있으므로, 이 RegSvr32에 해당 컨트롤에 대한 .OCX 파일의 전체 경로 및 파일 이름을 인수로 전달하기만 하면 됩니다. MFC ActiveX 컨트롤 REGSVR 샘플에는 RegSvr32.EXE에 대한 소스 코드가 포함되어 있습니다. 이 샘플은 등록 작업을 수행하는 데 사용할 수 있는 방법에 대한 한 가지 예로, 사용자가 직접 등록 루틴을 만들 때 지침으로 사용할 수 있습니다.

원하는 경우에는 사용자 대신 설치 프로그램에서 컨트롤을 직접 등록하도록 만들 수도 있습니다.

LoadLibrary Windows API를 사용하여 해당 컨트롤의 DLL을 로드합니다. 그런 다음, GetProcAddress를 사용하여 "DllRegisterServer" 함수의 주소를 가져옵니다. 마지막으로, DllRegisterServer 함수를 호출합니다. 다음 코드 샘플에서는 이 경우에 사용할 수 있는 한 가지 방법을 보여 줍니다. 여기에서 hLib에는 컨트롤 라이브러리의 핸들이 저장되고 lpDllEntryPoint에는 "DllRegisterServer" 함수의 주소가 저장됩니다.

 

 

HINSTANCE hLib = LoadLibrary(pszDllName);

if (hLib < (HINSTANCE)HINSTANCE_ERROR)
{
   DisplayMessage(IDS_LOADLIBFAILED, pszDllName); //unable to load DLL
   iReturn = FAIL_LOAD;                           //unable to load DLL
}

// Find the entry point.
(FARPROC&)lpDllEntryPoint = GetProcAddress(hLib,
   _T("DllRegisterServer"));
if (lpDllEntryPoint != NULL)
   (*lpDllEntryPoint)();
else
   // Unable to locate entry point

 


컨트롤을 직접 등록하면 별도의 프로세스(즉, REGSVR32)를 호출하거나 로드할 필요가 없으므로 설치 시간이 줄어든다는 장점이 있습니다. 또한 이 경우 등록 작업은 내부 프로세스이기 때문에 외부 프로세스보다는 설치 프로그램에서 오류 및 예측할 수 없는 상황을 좀 더 적절하게 처리할 수 있습니다.

참고   설치 프로그램에서 ActiveX 컨트롤을 설치하기 전에 OleInitialize를 호출해야 합니다. 또한 설치 프로그램을 종료할 때에는 OleUnitialize를 호출해야 합니다. 그래야만 OLE 시스템 DLL이 ActiveX 컨트롤을 올바르게 등록할 수 있습니다.
MFCx0.DLL은 사용자가 등록해야 합니다.


출처: http://msdn.microsoft.com/ko-kr/library/cc451427(VS.71).aspx

Posted by SB패밀리

DLL이나 OCX를 레지스트리에 등록하거나 제거..
regsvr32를 이용한다..

예)
regsvr32 "C:ProjectNeoTest 2.60_Output_Debugeoweboardax.ocx"
regsvr32 /u  "C:ProjectNeoTest 2.60_Output_Debugeoweboardax.ocx"
regsvr32 /s  "C:ProjectNeoTest 2.60_Output_Debugeoweboardax.ocx"
regsvr32 /s /u  "C:ProjectNeoTest 2.60_Output_Debugeoweboardax.ocx"
regsvr32 /s /c  "C:ProjectNeoTest 2.60_Output_Debugeoweboardax.ocx"

/u : Unregister
/s : Silent
/c : Console output

regsvr32는 DLL이나 OCX를 호출하고, DLL내부의 DllRegisterServer()과 DllUnregisterServer()을 호출하는 역할을 한다.
만약 regsvr32를 사용하지 않고 직접 등록하려면 다음과 같이 할 수 있다..(Devpia 참고..)

// Usage
AfxMessageBox( RegFunc("MsComm.ocx") );  

CString RegFunc(LPCTSTR lpOCXName) 
{

CString systemDir = _T("");
CString FindFileName = _T("");

::GetSystemDirectory(  systemDir.GetBuffer(255), 255);

FindFileName.Format("%s\%s", systemDir, lpOCXName);

HINSTANCE h = ::LoadLibrary(FindFileName);

if (h != NULL) {
FARPROC pFunc = ::GetProcAddress(h,"DllRegisterServer");
if (pFunc != NULL)
{
(*pFunc)();
} else {
FindFileName.Format("%s 등록 실패 되었읍니다.", lpDiscript);
return FindFileName; 
}
::FreeLibrary(h);

FindFileName.Format("%s 등록 되었읍니다.", lpDiscript);
return FindFileName;
} else {
FindFileName.Format("%s 등록 실패 되었읍니다.", lpDiscript);
return FindFileName;

}


출처: http://ninvu.egloos.com/1936098
Posted by SB패밀리

 MFC ActiveX를 만들기 할때 관련 DLL을 포함시켜야하는 경우가 있다.

 [App.Code]에 포함시킬 때 순서는 OCX 먼저 포함하고 DLL은 나중에 포함시켜야
DLL먼저 설치되고 나중에 OCX 파일이 실행되어 문제가 없다

AcitveX에 포함할 MFC 관련 DLL

MFC42.DLL
MSVCRT.DLL
OLEPRO32.DLL


참고로 ActiveX설치할 때 설치되는 OCX나 INF파일의 위치는
웹상에서 설치된 파일들의 정보
레지스트리는
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Code Store Database\Distrbution Units
폴더상에서는
C:\Windows\Downloaded Program Files
를 확인한다.

별도의 언인스톨 프로그램이 없다면
위의 레지스트리와 폴더상에서 해당 CLSID에 해당하는 파일이나 경로를 삭제하면 된다.

Posted by SB패밀리

INF파일 내용 포멧팅 혹은 구조에 대해 설명하는 문서이다


아래는 관련 내용
출처 : http://zoomout.egloos.com/949444


ActiveX Installer 만들기

ActiveX 를 만들다보면, Cab파일을 만들어서 배포하는데, 잘 안되는경우가 있습니다.

시스템을 리부팅해야 한다는둥, 이전버젼이 계속 안지워지고, 매번 계속 다운을 받는다든가

하는 상황이 발생할때가 있습니다.

물론 inf랑 cab파일 다 잘만들었을때 얘기죠

그래서 저는 , 강제로, 이전버젼의 aCtiveX를 강제로 삭제하고, 새로운버젼을 시스템 디렉토리에

복사한다음, regsvr32까지 해주는 프로그램을 만들어서 씁니다.

cab파일을 받았을때 AcitveX를 설치하고 등록하고 업데이트 하는 일을 명시적으로 직접

프로그램에서 하는거죠 .

 

Required Skill

1. ActiveX ( ???.ocx) 파일을 실행파일에 포함시키는 방법

2. 파일을 regsvr32 사용해서 실제로 등록 하는 방법 ( 로컬컴퓨터의 regsvr32 를 이용하는것이 아니라

실제 구현한 함수를 사용합니다. )

References

1. Q/A 보드 184574 번글, 이승훈님의 '바이너리 리소스'라는 제목의 글을 참조하십시오 .

2. Tip And Trick , 2039번글, 하형욱님(-_-)의 'Regsvr Function'이라는 제목의 글을 참조하십시오.


Logique

1. OCX를 resource에 넣어서, exe파일에 같이 들어가게 합니다.

2. exe가 실행되면 , resource에 있는 ocx 파일을 로컬컴퓨터의 System Directory에 복사합니다.

 ( modeCreate 해서 이전파일을 지워주시구요 )

3. regsvr 함수를 사용하여 복사한 ocx를 등록해줍니다.


Another Information

CAB파일을 만들때는 다음과 같이 INF 파일을 만들어줍니다.


[Version]
signature="$CHICAGO$"
AdvancedINF=2.0

[Setup Hooks]
InstallHook=InstallHook

[InstallHook]
run=%EXTRACT_DIR%컴파일해서만든프로그램이름.exe -remote


웹페이지에 넣을때는 OCX 를 기준으로 해서 하던 것 처럼 해주시구요.

cab파일 만들때는 . exe랑 inf 만 해주면 되겠지요. , OCX에 대한 정보가 없으니 inf가 정말 간단해졌습니다.

 

그럼 로컬에 있는 버젼을 체크해서 버젼이 낮으면 

서버에 있는 cab파일을 다운받고 ( 여기까지는 자동이죠? )

inf 있는 내용대로 설치를 시작합니다.

위와 같이 적어져먼 InstallHook에 명시된 프로그램이 실행되므로,

우리가 프로그래밍한대로 , 수동으로 ocx복사하고, 등록까지 되겠죠. 

 

장점 :   설치를 프로그램에서 명시적으로 하므로 , 설치때 특별한 일을 해줄수 있습니다.

            (만든 사람이름을 따로 보여준다든가. .등등의. )

단점 : cab파일의 크기가 커집니다. 프로그램이 60k 가 좀 넘으므로, Ocx 를 패키징 하는것보다

         몇십 K 정도 더 커지겠죠.

 

바이너리 리소스...
1. 자신을 오픈하는 방법
CreateFile()에 FILE_SHARE_READ 옵션을 주시면 가능할 것도 같은데 해보지 않아서 장담
할 수 없군요.

2. 실행 파일에 합치는 방법

프로그램의 리소스에 바이너리 데이터를 추가할 수 있습니다.
컴파일이 될 때 합쳐집니다.


(프로젝트명).rc2에 아래와 같이 추가합니다.

/////////////////////////////////////////////////////////////////////////////
// Add manually edited resources here...
IDR_DATA1 DATA Data.zip

/////////////////////////////////////////////////////////////////////////////

IDR_DATA1은 리소스 데이터를 오픈할 때 쓸 이름입니다.
DATA는 리소스의 종류입니다.
Data.zip은 실제 파일명입니다.
프로젝트의 소스코드가 있는 폴더에 파일이 존재해야 에러없이 컴파일됩니다.
(즉, 컴파일 될 때 실행 파일 안으로 합쳐집니다.)

아래의 함수를 참고해서 사용하시기 바랍니다.

BOOL CTestDlg::SaveResource(LPTSTR lpName, LPTSTR lpPathName)
{
   BOOL bRtn;
   LPTSTR lpRes;
   HRSRC hResInfo;
   HANDLE hRes;
   DWORD dwSize;
  
   // Find the wave resource.
   hResInfo = FindResource (NULL, lpName, "DATA");
  
   if (hResInfo == NULL)
       return FALSE;
  
   // Load the wave resource.
   hRes = LoadResource (NULL, hResInfo);
  
   if (hRes == NULL)
       return FALSE;
  
   // Get size of resource.
   dwSize = SizeofResource(NULL, hResInfo);

   // Lock the wave resource and play it.
   lpRes = (LPTSTR)LockResource (hRes);

  
   if (lpRes != NULL)
        { // 실제 파일로 저장하는 부분
       CFile file;
       file.Open(lpPathName, CFile::modeCreate|CFile::modeWrite);
       file.Write(lpRes, dwSize);
       file.Close();
        }
   else
       bRtn = 0;
  
   return bRtn;
}


그럼...


Regsvr Function

regsvr32 소스가 있길래 거기서 함수를 간추려 올립니다.
파라메터에는 등록할 라이브러리 경로를 적어주시면 되겠죠..
등록해지 할때는 중간의 _szDllRegSvr 값을 _szDllUnregSvr로 교체 해 주심됩니다.

#include
#include
#include
#include

#define FAIL_ARGS   1
#define FAIL_OLE    2
#define FAIL_LOAD   3
#define FAIL_ENTRY  4
#define FAIL_REG    5

int regLib (const char *LibraryName)
{   
const char* _szDllRegSvr = "DllRegisterServer";
const char* _szDllUnregSvr = "DllUnregisterServer";

int iReturn = 0;
   HRESULT (STDAPICALLTYPE * lpDllEntryPoint)(void);

   BOOL bVisualC = FALSE;
   BOOL bUnregister = FALSE;
   LPCSTR pszDllEntryPoint = _szDllRegSvr;
   LPCSTR pszDllName = LibraryName;

   if (FAILED(OleInitialize(NULL))) {
       return FAIL_OLE;
   }

   SetErrorMode(SEM_FAILCRITICALERRORS); 

       HINSTANCE hLib = LoadLibraryEx(pszDllName, NULL,
LOAD_WITH_ALTERED_SEARCH_PATH);

       if (hLib < (HINSTANCE)HINSTANCE_ERROR) {
           TCHAR szError[12];
           wsprintf(szError, _T("0x%08lx"), GetLastError());

           iReturn = FAIL_LOAD;
           goto CleanupOle;
       }

       (FARPROC&)lpDllEntryPoint = GetProcAddress(hLib,
pszDllEntryPoint);

       if (lpDllEntryPoint == NULL) {
           TCHAR szExt[_MAX_EXT];
           _tsplitpath(pszDllName, NULL, NULL, NULL, szExt);

           if ((_stricmp(szExt, ".dll") != 0) && (_stricmp
(szExt, ".ocx") != 0))
           {
      
           }
           else
           {
              
           }

           iReturn = FAIL_ENTRY;
           goto CleanupLibrary;
       }

      
       if (FAILED((*lpDllEntryPoint)())) {
           iReturn = FAIL_REG;
           goto CleanupLibrary;
       }

CleanupLibrary:
       FreeLibrary(hLib);
  
CleanupOle:
   OleUninitialize();

   return iReturn;
}


Posted by SB패밀리

Cabarc 사용법

실행화일을 배포하기 위해 일반적으로 사용하는 것이 CAB화일 형태로 만든 다음 하나의 CAB화일을 OBJECT Tag로 넣어 HTML에 삽입 하는 것입니다. dll이나 ocx 또는 다른 cab화일을 통해 새로운 CAB화일을 만들 수 있습니다. CAB화일은 다운로드를 위해 압축을 하는 일종의 압축포맷입니다.

1. CAB 파일 생성방법

Usage: CABARC [options] command cabfile [@list] [files] [dest_dir]
 기본 예> cabarc -s 6144 N my.cab my1.ocx my2.ocx

  1. 하나의 파일을 Cab 파일로 생성
      CabArc n my.cab my.ocx

  2. 적은수의 파일을 Cab 파일로 생성
     - 3개의 파일(my.ocx, my2.ocx, my.inf)로 Cab 파일 생성
      Cabarc n my.cab my1.ocx my2.ocx my.inf

  3. 많은수의 파일을 Cab 파일로 생성
     - 파일들을 하나의 하위 디렉토리(예:app)에 넣고 바로 위 디렉토리에서 다음의 명령을 이용한다.
      Cabarc r ?p my.cab app\*.*

2. Cabarc 옵션리스트

  1. Command
    L Cabinet(CAB) 파일의 목록 보기 (예: CabArc l my.cab)
    N 새로운 cabinet 파일 생성 (예: CabArc n my.cab *.dll *.ocx)
    X Cabinet 파일로부터 파일 꺼내기 (예: CabArc x my.cab my.ocx)

  2. Options
    -c 작업할 파일 확인하기
    -o 파일을 꺼낼 때, 사용자에게 묻지 않고 덮어쓰기
    -m 압축 형태 지정 [LZX:<15..21>|MSZIP|NONE], (기본 형태는 MSZIP)
    -p 파일명에 파일 경로 포함하기 (단, 상대 경로만 허용)
    -P 파일 포함 시 지정된 접두어 생략하기 (주로, 파일 경로의 일부가 지정됨)
    -r 하위 디렉토리의 파일까지 포함하기 (주로, -p 옵션과 함께 사용)
    -s Cabinet 파일 내에 사인 정보를 둘 여유 공간 확보 (예: -s 6144 => 6K bytes)
    -I Cabinet 생성시 'Cabinet Set ID' 지정 (기본 아이디는


출처 : http://www.certkorea.co.kr/doc.asp?g_dev_cabarc

Posted by SB패밀리