[까막] 고속 추가 전용 - 리스트 컨트롤   | VC++ 컨트롤관련 2002-08-07 오전 11:57:17
까막 (crowback)  까막님께 메시지 보내기까막님을 내 주소록에 추가합니다.까막님의 개인게시판 가기 번호: 12923   / 평점:  (-)  / 읽음:2,929
MFC Virtual List Control -  Andrew Small by codeguru site;
먼저 여기 사용된 부분은 코드구루의 앤드류 스몰의 자료를 수정한 것입니다.
앤드류의 소스는 CLabelItem 클래스를 사용자가 직접 수정하거나, 데이터를 삽입할 때마가 불필요한 코딩이
필요하고, 또한 데이터를 한꺼번에 삽입하는것만 가능하도록 설계되어 있어 불편한 점이 조금 있습니다.

위의 소스를 수정하여.. Insert 없이 Add 전용의 고속 리스트 컨트롤을 만들어 보았습니다.
이러한 리스트는 수시로 없데이트 되는 데이터가 아닌, 로그 값이나 특정 수치값을 계속적으로 쌓아 놓는
구조에 알맞습니다.
만약 인터넷 트레픽을 수치상으로 시간과 장소, 대역폭, 사용데이트 등을...
시간대별로 계속 쌓아서 감시를 한다던가.. 하는 것.. 혹은...

여러군대에서 발생한 자료를 시간대 별로 한꺼번에 몰아서 데이터를 읽어 와 리스트에 쌓는다던가 하는
작업에 맞게 구성되었습니다.

원래의 InsertItem() 를 막고, AddItem() 함수로 대치하였습니다.
SetItemText() 함수와 GetItemText() 함수는 그대로 적용됩니다.
DeleteItem()는 삭제되었고,
DeleteAllItems() 함수도 그대로 적용됩니다.

테스트 결과 3개의 컬럼이고, 각각 10여바이트 정도의 문자열을 텍스트를 갖는경우.
약 20000 개 정도의 데이터를 삽입하는데 걸리는 시간은 P3 933, RAM 256, Release Mode에서
삽입과 화면 업데이트까지 약 0.7초 정도 걸립니다.

각각 컬럼별로 헤더에서 오름차순 정렬 혹은 내림차순 정열은 각각 0.2-0.3초 정도 소요됩니다.

물론 레포트 타입 전용입니다.
이미지 리스트도 지원하지 않습니다.

그럼 이만..

 [까막] 코딩으로 휴지통 복구하기..  | ActiveX/COM 2003-11-04 오후 6:16:46
까막 (crowback)  까막님께 메시지 보내기까막님을 내 주소록에 추가합니다.까막님의 개인게시판 가기 번호: 16893   / 평점:  (-)  / 읽음:1,749

질문에 답변 하나 달으려다 엄청난 시간이 날라갔네요. 조만간에 모가지가 될지도 ㅡㅜ;


휴지통에 보내기는 많이 보내봤는데.. 휴지통에 있는 넘을 복구하는 방법은 Undocumented라.. MSDN을

찾아봐도 껀덕지 나오는게 없더군요..


결국 쉘폴더를 불러서, 아이템을 얻고, 해당 아이템의 숏컷 핸들러를 얻은다음 Invoke 해주는

방법을 취했습니다.


동작은 잘되더군요..


1. 휴지통의 IShellFolder2 인터페이스를 얻어 온다.

2. IShellFolder2::EnumObjects() 를 이용하여 IEnumIDList 값을 긁어 들인다.

3. IEnumIDList::Next() 메서드를 이용하여, 개별적인 ITEMIDLIST 값들을 하나씩 읽어 온다.

4. 각각 읽어 온넘들을 pidl 이라 치면, 해당하는 IContextMenu 인터페이스를 얻는다.

5. IContextMenu::QueryContextMenu, IContextMenu::GetCommandString, IContextMenu::InvokeCommand

   메서드들을 적당한 인자를 주어 호출하여, 선택된 아이템을 복구한다.


대략 위와 같은 구조로 동작하구요..

 

참고 사항으로

 

휴지통에 떤지기 : SHFileOperation

휴지통을 비우기 : SHEmptyRecycleBin

휴지통에 들은 파일 갯수와 크기 얻기 : SHQueryRecycleBin

 

이런 함수들이 있습니다.


MSDN에서 참고 하실만한 페이지에는

1. Managing the File System

    SHFileOperation 함수를 사용하는 응용예가 가장 자세히, 그리고 Notify와 Recent 연동까지.. 잘 나와있습니다.

2. Shell Functions

    일반적으로 다루는 쉘함수들의 리스트가 쭉 나와 있구요, 평소에 접하지 못하는 혹은 필요한데 못찾던것들 까지

    잘 구분되어 있습니다.


그럼 즐거운 한주 되세요...


이 글에 평점 주기:  
[코멘트]  2003-11-17 17:42:00
조갑열 (cgl777)   조갑열님께 메시지 보내기조갑열님을 내 주소록에 추가합니다.조갑열님의 개인게시판 가기 
ecycleBinDlg.cpp
F:\download\휴지통 복구\RecycleBinDlg.cpp(9) : fatal error C1083: Cannot open include file: 'ShObjIdl.h': No such file or directory
Generating Code...
Error executing cl.exe.
Creating browse info file...
BSCMAKE: error BK1506 : cannot open file '.\Debug\RecycleBinDlg.sbr': No such file or directory
Error executing bscmake.exe.

RecycleBin.exe - 2 error(s), 0 warning(s)
이 에러는 뭘까요..ㅠ.ㅠ?
 
[코멘트]  2003-11-17 19:50:00
까막 (crowback)   까막님께 메시지 보내기까막님을 내 주소록에 추가합니다.까막님의 개인게시판 가기 
ShObjIdl.h' 파일을 찾을 수 없다는 에러 메시지네요..
위의 헤더 파일을 사용하시려면 Platform SDK를 설치하셔야 합니다.
DWORD Err;

PIP_ADAPTER_INFO pAdapterInfo, pAdapt;

DWORD AdapterInfoSize = 0;

PIP_ADDR_STRING pAddrStr;



//버퍼 사이즈 알아오기

if ((Err = GetAdaptersInfo(NULL, &AdapterInfoSize)) != 0)

if (Err != ERROR_BUFFER_OVERFLOW)

return FALSE;



//버퍼 동적 할당

if ((pAdapterInfo = (PIP_ADAPTER_INFO)new BYTE[AdapterInfoSize]) == NULL)

return FALSE;



//어댑터 정보 얻어오기

if ((Err = GetAdaptersInfo(pAdapterInfo, &AdapterInfoSize)) != 0)

return FALSE;



pAdapt = pAdapterInfo;



int i=0;

while (pAdapt) -->이반복문에서 랜카드 갯수 만큼 루프를 돌면서 주소값을 얻어옵니다.

{

pAddrStr=&(pAdapt->IpAddressList);

g_sClientinternalsockaddr.bySockaddrcount=(i+1);



while(pAddrStr)

{

g_sClientinternalsockaddr.asockaddr[i].sin_addr.S_un.S_addr=inet_addr(pAddrStr->IpAddress.String);

pAddrStr = pAddrStr->Next;

}

pAdapt = pAdapt->Next;

i++;

}

delete pAdapterInfo;

pAdapterInfo=NULL;





혹은





// 로컬 어드레스를 세트한다.

char recvline[300];

gethostname(recvline, 200);



// 이름으로부터 IP를 얻어낸다.

struct hostent *pHostEnt = gethostbyname(recvline);



if (pHostEnt != NULL)

{

localAddress.Format("%u.%u.%u.%u",

0xff & pHostEnt->h_addr_list[0][0],

0xff & pHostEnt->h_addr_list[0][1],

0xff & pHostEnt->h_addr_list[0][2],

0xff & pHostEnt->h_addr_list[0][3]

);

} else

localAddress = _T("");
// 주어진 크기만큼 공백을 삽입한다.

static void Blank(int n)

{

int k = 16-n;

k = k*3 + (n<7?1:0);

for(int i=0; i<k; i++)

printf(" ");

}



// 바이너리 데이터를 정규 포멧으로 출력한다.

void PrintBinary(BYTE* buffer, int length)

{

int row = length/16;

int col = length%16;

int i, j;

int prev = 0;

for(i=0; i<=row; i++)

{

int end = 16;

if(i == row)

end = col;

else

end = 16;



printf("%06X  ", i*16);



for(j=0; j<end; j++)

{

printf("%02X ", buffer[i*16+j]);

if(j==7)

printf(" ");

}

Blank(end);

printf("    ");

for(j=0; j<end; j++)

{

char ch = buffer[i*16+j];

char ch1 = buffer[i*16+j+1];

if(isprint(ch))

printf("%c", ch);

else

{

if((ch >> 7) & 0x01 == 1 && (ch1 >> 7) & 0x01 == 0 && prev == 0)

{

printf("%c", ch);

prev = 1;

}

else

{

if(prev == 1)

{

printf("%c", ch);

prev = 0;

}

else

printf(".");

}

}



if(j==7)

printf(" ");

}



printf("\n");

}

}



// 바이트 데이터를 이진수 문자열로 출력한다.

void PrintByte(BYTE ch)

{

for(int i=0; i<8; i++)

printf("%c", (ch>>(7-i)&0x01)?'1':'0');

현재 이넘은 윈XP만 지원한덴다.

typedef HRESULT (WINAPI MF)(HWND hwndParent, LPCWSTR pszPath);

void CAaaDlg::OnButton1()
{
HMODULE hm = ::LoadLibrary("ntshrui.dll");
if(!hm)
return;

MF* proc = (MF*)GetProcAddress(hm, "ShowShareFolderUIW");

wchar_t str[] = L"C:\\Windows\\";

if(proc)
{
HRESULT f = proc(m_hWnd, str);
int a = 0;
}

::FreeLibrary(hm);
}
올리기올려짐: 토 8월 12, 2006 1:22 am    주제: [팁] 풀 스크린 (SDI/ MDI) 인용과 함께 답변 글 편집/삭제 글 삭제 글 올린이의 IP 주소 보기

메인 프레임 헤더...

BOOL m_IsFullScreen;
WINDOWPLACEMENT m_wpPrev;
void SetFullScreen();


메인 프레임 소스...

void CMainFrame::SetFullScreen()
{
WINDOWPLACEMENT wpNew;
CRect rectDesktop;

if (!m_IsFullScreen)
{
// 툴바와 상태바를 감춘다.
m_wndStatusBar.ShowWindow(SW_HIDE);
m_wndToolBar.ShowWindow(SW_HIDE);

// 현재 윈도우의 위치를 얻어온다.
GetWindowPlacement (&m_wpPrev);
m_wpPrev.length = sizeof m_wpPrev;

::GetWindowRect ( ::GetDesktopWindow(), &rectDesktop );
::AdjustWindowRectEx(&rectDesktop, GetStyle(), TRUE, GetExStyle());

wpNew = m_wpPrev;
wpNew.showCmd = SW_SHOWNORMAL;
wpNew.rcNormalPosition = rectDesktop;
m_IsFullScreen=TRUE;
}
else
{
m_IsFullScreen=FALSE;
// 툴바와 상태바를 보여준다.
m_wndStatusBar.ShowWindow(SW_SHOWNORMAL);
m_wndToolBar.ShowWindow(SW_SHOWNORMAL);
wpNew = m_wpPrev;
}

SetWindowPlacement ( &wpNew );
}

void CMainFrame::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI)
{
CRect rectDesktop;
::GetWindowRect ( ::GetDesktopWindow(), &rectDesktop );
::AdjustWindowRectEx(&rectDesktop, GetStyle(), TRUE, GetExStyle());
// 윈도우의 최대 사이즈를 얻어온다.
if (m_IsFullScreen)
{
lpMMI->ptMaxSize.y = rectDesktop.Height();
lpMMI->ptMaxTrackSize.y = lpMMI->ptMaxSize.y;
lpMMI->ptMaxSize.x = rectDesktop.Width();
lpMMI->ptMaxTrackSize.x = lpMMI->ptMaxSize.x;
}
CFrameWnd::OnGetMinMaxInfo(lpMMI);
}

BOOL CMainFrame::PreTranslateMessage(MSG* pMsg)
{
//ALT + Enter를 누르면 풀 스크린이당 ^^
if(pMsg->message == WM_SYSKEYDOWN && pMsg->lParam == 0x201C0001)
SetFullScreen();
return CFrameWnd::PreTranslateMessage(pMsg);
}


MDI 일경우는...
차일드 프레임 소스...
void CChildFrame::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI)
{
CMainFrame* pFrame = (CMainFrame*)AfxGetMainWnd();
if(pFrame)
{
CRect rectDesktop;
::GetWindowRect ( ::GetDesktopWindow(), &rectDesktop );
::AdjustWindowRectEx(&rectDesktop, GetStyle(), TRUE, GetExStyle());
// 윈도우의 최대 사이즈를 얻어온다.
if (pFrame->m_IsFullScreen)
{
lpMMI->ptMaxSize.y = rectDesktop.Height();
lpMMI->ptMaxTrackSize.y = lpMMI->ptMaxSize.y;
lpMMI->ptMaxSize.x = rectDesktop.Width();
lpMMI->ptMaxTrackSize.x = lpMMI->ptMaxSize.x;
}
}

CMDIChildWnd::OnGetMinMaxInfo(lpMMI);
}
HINSTANCE FindExecutableEx(... 인자는 동일하다 ...)
{
TCHAR drive[_MAX_DRIVE];
TCHAR dir[_MAX_DIR];
TCHAR dir1[_MAX_DIR];
TCHAR file[_MAX_FILE];
TCHAR ext[_MAX_EXT];

HINSTANCE hi = FindExecutable(file, dir, result);
result[lstrlen(result)] = 32;

_splitpath(result, deive, dir, file, ext);

LPTSTR p = strchr(dir, ':');
if(p != NULL)
{
--p;
dir[p-dir] = 0;
_splitpath(dir, NULL, dir1, file, ext);
p = strchr(ext, 32);
ext[p-ext] = 0;
_makepath(result, drive, dir1, file, ext);
}
return hi;
}
약속한데로... 자세한 설명을 해 드리죠.

1. 초기화 과정입니다.

BOOL CCaptureDlg::OnInitDialog()
{
// VC++ 에서 지원한는 Smart Poniter 라는 것으로 구현 했습니다.
// 전병선씨가 지은 ATL/COM 프로그램밍 책에 보시면 자세히 설명하는데
// 사 보셔도 좋고요. 앞으로 ATL 을 공부하시는데 도움이 될겁니다.
// 연락 주시면 가지고 있는 COM 관련 추천 책들도 알려 드리죠.


// InitInstance() 에 AfxOleInit() 가 추가 되어 있는지 확인한다.
m_pZlib = IZlibAtlPtr(__uuidof(ZlibAtl));

// 만일 ZlibUtil 이 이벤트를 받고 싶을때 다음의 리마크를 없애세요.
// 이벤트 처리는 ZlibUtil 가 같이 샘플로 제공된 createzipstg 에 이벤트
// 처리를 윈한 코드들이 들어 갔으니까 참고 하세요.
// 만일 안 쓰시겠다면 다음 코드들은 지워도 됩니다.

// m_pEvent = new CZlibEvent(this);
// BOOL bAdvised = AfxConnectionAdvise(m_pZlib, DIID__IZlibAtlEvents,
// m_pEvent->GetInterface(&IID_IUnknown),
// TRUE, &m_dwCookie);
}


2. 캡쳐 하기입니다.

void CCaptureDlg::OnCapture()
{
// TODO: Add your control notification handler code here
UpdateData(TRUE);

// CDib 는 밑에 김서영님의 올린 것을 Wrap 한 함수입니다.
// 참고해서 읽어 보세요.

CDib dib;
CRect rect(atoi(m_szX),atoi(m_szY),atoi(m_szX)+atoi(m_szW),atoi(m_szY)+atoi(m_szH));
CSize destSize(atoi(m_szW),atoi(m_szH));

if(m_hDIB) {
GlobalFree(m_hDIB); // 전에 가지고 있던 메모리를 해제함.
}

UINT size;
dib.WriteWindowToDIB(rect, destSize, m_hDIB, size);

HBITMAP hBitmap;

// BitmapFromDib 는 MS 사 ShowDib(dib.c) 라는 샘플에 있던 것으로
// Bitmap Image 가지고 할수 있는 Wrap 함수들입니다.
// 쓸만한것이 상당히 많으니까 한번씩 이름만이라도 보시면 도움이
// 되겠군요.
hBitmap = BitmapFromDib (m_hDIB, NULL);

// m_Picture.m_pPict 는 CPitureHodler 라는 클래스로 ActiveX
// 의 Picture Proprety 를 Wrap 클래스 입니다.
// 멤버 함수들은 MSDN 을 참고 하시고...
// 여기서는 그냥 BITMAP Handle 을 통해서 Picture 을 생성하면
// 되겠습니다.
m_Picture.m_pPict.CreateFromBitmap(hBitmap, NULL);

// 화면 재 갱신을 하시면 m_Picture 의 OnPaint() 에서
// 화면의 크기를 계산하고 m_pPict 의 Render 를 Call 해서
// 화면에 직접 그림니다.

// 게으른 관계로 ActiveX Picture Wrap Class 를 써서
// 화면 출력을 구현했습니다.
m_Picture.Invalidate();
}


3. 압축하기 인데 상당히 소스가 길어 보이죠...
파라미터로 화일명과 DIB 에 대한 핸들을 주면 됩니다.

BOOL CCaptureDlg::WriteDIBToZip( LPSTR szFile, HANDLE hdib)
{
BITMAPFILEHEADER hdr;
LPBITMAPINFOHEADER lpbi;

if (!hdib)
return FALSE;

lpbi = (LPBITMAPINFOHEADER)GlobalLock (hdib);

/* Fill in the fields of the file header */
// BITMPAP FILE 에 대한 설명이군요.
hdr.bfType = BFT_BITMAP;
hdr.bfSize = GlobalSize (hdib) + SIZEOF_BITMAPFILEHEADER_PACKED;
hdr.bfReserved1 = 0;
hdr.bfReserved2 = 0;
hdr.bfOffBits = (DWORD) (SIZEOF_BITMAPFILEHEADER_PACKED + lpbi->biSize +
PaletteSize(lpbi));

try {
/* Write the file header */

IStreamPtr pstrmInMem;
ULONG cbWritten = 0;
ULONG cbTotal = 0;
HRESULT hr = S_OK;

// 화일을 대신할 Stream 을 만든다.
// 하나의 화일로 되어 있으면 그것을 바로 메모리로 옮기고 압축하면
// 좋겠지만 그러하지 않으니까... 일단 만듭니다.
hr = CreateStreamOnHGlobal(NULL, TRUE, &pstrmInMem);
_com_util::CheckError(hr);

#ifdef FIXDWORDALIGNMENT
hr = pstrmInMem->Write(hdr, (UINT)(SIZEOF_BITMAPFILEHEADER_PACKED), &cbWritten);
_com_util::CheckError(hr);

cbTotal += cbWritten;
#else
/* write bfType*/
hr = pstrmInMem->Write(&hdr.bfType, (UINT)sizeof (WORD), &cbWritten);
_com_util::CheckError(hr);
cbTotal += cbWritten;

/* now pass over extra word, and only write next 3 DWORDS!*/
hr = pstrmInMem->Write(&hdr.bfSize, sizeof(DWORD) * 3, &cbWritten);
_com_util::CheckError(hr);
cbTotal += cbWritten;
#endif

/* this struct already DWORD aligned!*/
/* Write the DIB header and the bits */
hr = pstrmInMem->Write(lpbi, GlobalSize (hdib), &cbWritten);
_com_util::CheckError(hr);
cbTotal += cbWritten;

// 이제 pstrmInMem 는 Bitmap 화일과 같습니다.

// pstrmInMem 을 압축하겠습니다.
#ifdef USE_MEMORY // 메모리를 사용할 경우.

// SafeArray 는 컴퍼넌트간 메모리를 통한 복사를 위한 함수입니다.
// 1. Create 하기(Create)
// 2. 메모리를 Lock 하기(AccessData)
// 메모리를 데이타를 써넣고
// 3. 메모리를 UnLock 하기(UnaccessData)
// 4. Create 된것을 지우기 (Destroy)
_variant_t var;
PCHAR pBuf;
PBYTE pArr;
DWORD dwLen = cbTotal; // 크기 지정함
SAFEARRAY FAR* psa;
SAFEARRAYBOUND rgsabound[1];
rgsabound[0].lLbound = 0;
rgsabound[0].cElements = dwLen;
psa = SafeArrayCreate(VT_UI1, 1, rgsabound); //1. 동적으로 메모리 생성
if(psa == NULL) {
_com_issue_error(S_OK);
}

hr = SafeArrayAccessData(psa, (PVOID *)&pBuf); // 2. Lock 하기
_com_util::CheckError(hr);

memset(pBuf, 0, dwLen);

HGLOBAL global;
GetHGlobalFromStream(pstrmInMem, &global);

LPVOID pVoid = GlobalLock(global);
CopyMemory(pBuf, pVoid, dwLen); // 데이타 쓰기
GlobalUnlock(global);

hr = SafeArrayUnaccessData(psa); // 3. Unlock 하기
_com_util::CheckError(hr);

var.vt = VT_ARRAY|VT_UI1|VT_BYREF; // VARAINT (MSDN 참조) 에 ARRAY 를 포인터로
var.parray = psa; // 넘긴다고 지정함.
m_pZlib->PutMode(MEM_TO_ZMEM); // ZLibUtil 에게 메모리(SafeArray) 사용을
// 알림

m_pZlib->PutInMemory(var); // variant 데이타 넘김(이미 데이타는 저장됨)

hr = m_pZlib->Compress(); // ZLibUtil 에게 압축을 지시함
_com_util::CheckError(hr);

SafeArrayDestroy(psa); // 4. Create 된 데이타 지우기
_variant_t outvar; // 이미 압축된 결과 데이타는 컴퍼넌트 안에
outvar = m_pZlib->GetOutMemory(); // 들어 있다.
// ZLibUtil 에게 데이타 요구함(Variant)
LONG lLbound, lUbound; // Vairant(outvar) 에 이미 데이타가들어와 있음
hr = SafeArrayGetLBound(outvar.parray, 1, &lLbound); // 크기를 알아냄(최하)
_com_util::CheckError(hr);

hr = SafeArrayGetUBound(outvar.parray, 1, &lUbound); // 크기를 알아냄(최상)
_com_util::CheckError(hr);
hr = SafeArrayAccessData(outvar.parray, (PVOID *)&pArr); // 실제 데이타 위치
_com_util::CheckError(hr); // 메모리 포인터

ULONG StoreLen; // 받을때 SafeArray 쓰는 것도 같습니다.
// 이미 컴퍼넌트가 Create 했으므로 2,3 과정만 하면 됩니다.
// 4 과정은 컴퍼넌트가 수행할 겁니다.
StoreLen = lLbound + lUbound+1; // 실제 받을 데이타 크기.

CFile file;
if(file.Open(szFile, CFile::modeCreate | CFile::modeWrite) ) {
file.WriteHuge(pArr, StoreLen);
file.Close();
}
else {
hr = SafeArrayUnaccessData(outvar.parray); // 3과정
_com_util::CheckError(hr);

_com_issue_error(S_OK);
}

hr = SafeArrayUnaccessData(outvar.parray);
_com_util::CheckError(hr);


#else // Stream 으로 사용할 경우
IStreamPtr pstrmOutMem;

hr = CreateStreamOnHGlobal(NULL, TRUE, &pstrmOutMem); // OutStream
_com_util::CheckError(hr); // 메모리에 화일을 대신할 메모리 Stream 을 만든다.

m_pZlib->PutMode(STREAM_TO_ZSTREAM); // Stream 압축을 지정함

LARGE_INTEGER li;
li.LowPart = li.HighPart = 0;

pstrmInMem->Seek(li, STREAM_SEEK_SET, NULL); // 이미 써넣으면서 뒤로 위치했으므로
// 앞으로 되돌림.
m_pZlib->PutInStream(pstrmInMem); // In 지정
m_pZlib->PutOutStream(pstrmOutMem); // Out 지정

m_pZlib->Compress(); // 압축
pstrmOutMem->Seek(li, STREAM_SEEK_SET, NULL);// 컴퍼넌트가 보낸데이타를 맨앞에서
// 부터 읽을 준비를 함.

CFile file;
if(file.Open(szFile, CFile::modeCreate | CFile::modeWrite) ) {
while(TRUE) {
char buf[8192];
ULONG cbRead = 0;
pstrmOutMem->Read(buf, 8192, &cbRead); // 8192로 계속 읽어 옵니다.

if(cbRead == 0)
break;

file.Write(buf, cbRead);
}
file.Close();
}
else {
_com_issue_error(S_OK);
}

#endif
}
catch (_com_error e){
HRESULT hr = e.Error();
if(hr != S_OK)
ShowMessage(e);

GlobalUnlock (hdib); // Lock 된 데이타 UnLock 함
return FALSE;
}

GlobalUnlock (hdib);
return TRUE;
}

4. 읽어 오기

HANDLE CCaptureDlg::LoadDIBFromZip( LPSTR szFile)
{
BITMAPINFOHEADER bi;
LPBITMAPINFOHEADER lpbi;
DWORD dwLen = 0;
DWORD dwBits;
HANDLE hdib = NULL;
HANDLE h;
ULONG cbRead = 0;

/* Open the file and read the DIB information */
// 이미 메모리에 대한 설명은 저장하기에서 했으므로
// 간단히 Stream 으로 가지고 작업 하기로 하겠습니다.
try {
IStreamPtr pstrmInMem;
IStreamPtr pstrmOutMem;
HRESULT hr = S_OK;

hr = CreateStreamOnHGlobal(NULL, TRUE, &pstrmInMem);
_com_util::CheckError(hr);

hr = CreateStreamOnHGlobal(NULL, TRUE, &pstrmOutMem);
_com_util::CheckError(hr);

CFile file;

if(file.Open(szFile, CFile::modeRead)) {
while(TRUE) {
char buf[8192];
ULONG cbWritten = 0;
UINT cbRead = file.Read(buf, 8192);

if(cbRead == 0)
break;

pstrmInMem->Write(buf, cbRead, &cbWritten);
}

m_pZlib->PutMode(ZSTREAM_TO_STREAM); // 압축된 스트림에서 스트림으로

LARGE_INTEGER li;
li.LowPart = li.HighPart = 0;

pstrmInMem->Seek(li, STREAM_SEEK_SET, NULL); // 읽어 오면서 뒤로간
// InStream 을 되 돌림
m_pZlib->PutInStream(pstrmInMem); // InStream 지정
m_pZlib->PutOutStream(pstrmOutMem); // OutStream 지정

m_pZlib->Decompress(); // 풀기
pstrmOutMem->Seek(li, STREAM_SEEK_SET, NULL);// 컴퍼넌트에서 온 데이타를
// 앞에서 쓸수 있도록 되돌림
}
else
return NULL;

file.Close();
hdib = ReadDibBitmapInfoFromStream(pstrmOutMem);
//ReadDibBitmapInfo 라는 함수가 있는데 이것은 화일 핸들로 파라미터로
//받는데 단지 Stream 을 받을수 있도록 수정했을뿐 내부 내용은
//ReadDibBitmapInfo 가 같습니다.
if (!hdib)
return NULL;
DibInfo(hdib,&bi);

/* Calculate the memory needed to hold the DIB */
dwBits = bi.biSizeImage;
dwLen = bi.biSize + (DWORD)PaletteSize (&bi) + dwBits;

/* Try to increase the size of the bitmap info. buffer to hold the DIB */
h = GlobalReAlloc(hdib, dwLen, GHND);
if (!h){
GlobalFree(hdib);
hdib = NULL;
}
else
hdib = h;

/* Read in the bits */
if (hdib){

lpbi = (LPBITMAPINFOHEADER)GlobalLock(hdib);

pstrmOutMem->Read((LPSTR)lpbi + (WORD)lpbi->biSize + PaletteSize(lpbi), dwBits, &cbRead);
GlobalUnlock(hdib);
}
}
catch (_com_error e){

}

return hdib;
}




이름 : 김서영 번호 : 52 게시일 : 1999.10.15 18:39:58 조회 : 196

안녕하세요
김서영입니다.
전에 시삽님이 올려놓으라고 하셨는데 지금에서야 올립니다.
죄송합니다.
Codeguru에서 가져온건데 제가 따로있는것을 붙여서 조금 수정했습니다.
많이는 아니고요

감사합니다.

BOOL CDib::WriteWindowToDIB(CRect &rect, CSize &destSize,HANDLE& hDIB, UINT& size)
{
CBitmap bitmap;
CDC memDC,screenDC;

screenDC.CreateDC("DISPLAY",NULL,NULL,NULL);
memDC.CreateCompatibleDC(&screenDC);
bitmap.CreateCompatibleBitmap(&screenDC, destSize.cx, destSize.cy);
CBitmap* pOldBitmap = memDC.SelectObject(&bitmap);
//영역에 대한 캡쳐 BitBlt를 이용해도 되는데..........
memDC.StretchBlt(0,
0,
destSize.cx,
destSize.cy,
&screenDC,
rect.left,
rect.top,
rect.Width(),
rect.Height(),
SRCCOPY);
CPalette pal;
//현재 해상도가 256칼라 이하라면 팔레트 추가
if( screenDC.GetDeviceCaps(RASTERCAPS) & RC_PALETTE )
{
UINT nSize = sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY) * 256);
LOGPALETTE *pLP = (LOGPALETTE *) new BYTE[nSize];
pLP->palVersion = 0x300;
pLP->palNumEntries = GetSystemPaletteEntries(
screenDC,
0,
255,
pLP->palPalEntry );
// Create the palette
pal.CreatePalette( pLP );
delete[] pLP;
}

memDC.SelectObject(pOldBitmap);

// Convert the bitmap to a DIB
hDIB = NULL;
hDIB = DDBToDIB(bitmap, BI_RGB, &pal , size);

screenDC.DeleteDC();

if( hDIB == NULL )
return FALSE;

return TRUE;
}

HANDLE CDib::DDBToDIB(CBitmap& bitmap, DWORD dwCompression, CPalette* pPal, UINT &size)
{
BITMAP bm;
BITMAPINFOHEADER bi;
LPBITMAPINFOHEADER lpbi;
DWORD dwLen;
HANDLE hDIB;
HANDLE handle;
HDC hDC;
HPALETTE hPal;

ASSERT( bitmap.GetSafeHandle() );

// The function has no arg for bitfields
if( dwCompression == BI_BITFIELDS )
return NULL;

// If a palette has not been supplied use defaul palette
hPal = (HPALETTE) pPal->GetSafeHandle();
if (hPal==NULL)
hPal = (HPALETTE) GetStockObject(DEFAULT_PALETTE);

// Get bitmap information
bitmap.GetObject(sizeof(bm),(LPSTR)&bm);

// Initialize the bitmapinfoheader
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = bm.bmWidth;
bi.biHeight = bm.bmHeight;
bi.biPlanes = 1;
bi.biBitCount = bm.bmPlanes * bm.bmBitsPixel;
bi.biCompression = dwCompression;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;

// Compute the size of the infoheader and the color table
int nColors = (1 << bi.biBitCount);
if( nColors > 256 )
nColors = 0;
dwLen = bi.biSize + nColors * sizeof(RGBQUAD);

// We need a device context to get the DIB from
hDC = ::GetDC(NULL);
hPal = SelectPalette(hDC,hPal,FALSE);
RealizePalette(hDC);

// Allocate enough memory to hold bitmapinfoheader and color table
hDIB = GlobalAlloc(GMEM_FIXED,dwLen);

if (!hDIB){
SelectPalette(hDC,hPal,FALSE);
::ReleaseDC(NULL,hDC);
return NULL;
}

lpbi = (LPBITMAPINFOHEADER)hDIB;

*lpbi = bi;

// Call GetDIBits with a NULL lpBits param, so the device driver
// will calculate the biSizeImage field
GetDIBits(hDC,
(HBITMAP)bitmap.GetSafeHandle(),
0L,
(DWORD)bi.biHeight,
(LPBYTE)NULL,
(LPBITMAPINFO)lpbi,
(DWORD)DIB_RGB_COLORS);

bi = *lpbi;

// If the driver did not fill in the biSizeImage field, then compute it
// Each scan line of the image is aligned on a DWORD (32bit) boundary
if (bi.biSizeImage == 0){
bi.biSizeImage = ((((bi.biWidth * bi.biBitCount) + 31) & ~31) / Cool
* bi.biHeight;

// If a compression scheme is used the result may infact be larger
// Increase the size to account for this.
if (dwCompression != BI_RGB)
bi.biSizeImage = (bi.biSizeImage * 3) / 2;
}

// Realloc the buffer so that it can hold all the bits
dwLen += bi.biSizeImage;
if (handle = GlobalReAlloc(hDIB, dwLen, GMEM_MOVEABLE))
hDIB = handle;
else{
GlobalFree(hDIB);

// Reselect the original palette
SelectPalette(hDC,hPal,FALSE);
::ReleaseDC(NULL,hDC);
return NULL;
}

// Get the bitmap bits
lpbi = (LPBITMAPINFOHEADER)hDIB;

// FINALLY get the DIB
BOOL bGotBits = GetDIBits( hDC,
(HBITMAP)bitmap.GetSafeHandle(),
0L, // Start scan line
(DWORD)bi.biHeight, // # of scan lines
(LPBYTE)lpbi // address for bitmap bits
+ (bi.biSize + nColors * sizeof(RGBQUAD)),
(LPBITMAPINFO)lpbi, // address of bitmapinfo
(DWORD)DIB_RGB_COLORS);// Use RGB for color table

if( !bGotBits )
{
GlobalFree(hDIB);

SelectPalette(hDC,hPal,FALSE);
::ReleaseDC(NULL,hDC);
return NULL;
}

SelectPalette(hDC,hPal,FALSE);
::ReleaseDC(NULL,hDC);
size = dwLen;

return hDIB;
}

//*******************************************************
// 팔레트 생성
//********************************************************
BOOL CDib::CreatePalette(HGLOBAL* hDIB, CPalette *pPal)
{
//수신된 데이타 영역에서 비트맵 정보영역을 추출
BITMAPINFO &bmInfo = *(LPBITMAPINFO)hDIB ;

//몇가지 색상을 사용하는지
int nColors = bmInfo.bmiHeader.biClrUsed ? bmInfo.bmiHeader.biClrUsed :
1 << bmInfo.bmiHeader.biBitCount;
// 256칼라 이하일때 팔레트의 생성
if( nColors <= 256 )
{
UINT nSize = sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY) * nColors);
LOGPALETTE *pLP = (LOGPALETTE *) new BYTE[nSize];
if( !(pLP)) pLP = (LOGPALETTE *) new BYTE[nSize];
if(pLP)
{
pLP->palVersion = 0x300;
pLP->palNumEntries = nColors;
}else return FALSE;

for( int i=0; i < nColors; i++)
{
pLP->palPalEntry[i].peRed = bmInfo.bmiColors[i].rgbRed;
pLP->palPalEntry[i].peGreen = bmInfo.bmiColors[i].rgbGreen;
pLP->palPalEntry[i].peBlue = bmInfo.bmiColors[i].rgbBlue;
pLP->palPalEntry[i].peFlags = 0;
}
pPal->CreatePalette( pLP );

delete[] pLP;
}
return TRUE;
}
IE가 죽을 때 트레이의 아이콘이 모두 사라지는 경우가 있습니다.
특히 트레이에 숨어버리는 프로그램이 그렇게 되면 참으로 난감해지죠.

IE 4이상에서는 그런 일을 막기 위해서 죽은 후 태스크바가 만들어질 때 모든 top-level 윈도우에 메시지를 보내줍니다. 그 메시지를 받으면 트레이에 새로 아이콘을 넣어주면 됩니다.

MSDN에 있는 내용이지만 모르시는 분들이 많더군요.

소스를 보면 다음과 같습니다.

LRESULT CALLBACK WndProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
{
static UINT s_uTaskbarRestart;

switch(uMessage)
{
case WM_CREATE:
s_uTaskbarRestart = RegisterWindowMessage(TEXT("TaskbarCreated"));
break;

default:
if(uMessage == s_uTaskbarRestart)
AddTaskbarIcons();
break;
}
return DefWindowProc(hWnd, uMessage, wParam, lParam);
}

RegisterWindowMessage(TEXT("TaskbarCreated")); 는 TaskbarCreated라는 이름의 메시지를 시스템에 대해서 유일하게 만들어주는 함수입니다. 이미 이 이름으로 메시지가 등록되어 있을 경우에는 그 값을 돌려줍니다.
따라서 프로그램이 시작할 때 한번 실행해서 그 값을 저장해줘야 합니다.
그리고 해당 메시지가 오면 그 때 트레이에 아이콘을 새로 넣으면 되겠죠.

MFC의 경우는 메시지의 값이 상수로 정해져 있지 않기 때문에 메시지 맵에 붙이는 건 안될 것 같습니다. CWnd::WindowProc이나 PretranslateMessage에서 메시지 값을 확인해서 처리해주면 되겠죠.
class CMemDC : public CDC {
private:
CBitmap* m_bitmap;
CBitmap* m_oldBitmap;
CDC* m_pDC;
CRect m_rcBounds;
public:
CMemDC(CDC* pDC, const CRect& rcBounds) : CDC()
{
CreateCompatibleDC(pDC);
m_bitmap = new CBitmap;
m_bitmap->CreateCompatibleBitmap(pDC, rcBounds.Width(), rcBounds.Height());
m_oldBitmap = SelectObject(m_bitmap);
m_pDC = pDC;
m_rcBounds = rcBounds;
}
~CMemDC()
{
m_pDC->BitBlt(m_rcBounds.left, m_rcBounds.top, m_rcBounds.Width(), m_rcBounds.Height(),
this, m_rcBounds.left, m_rcBounds.top, SRCCOPY);
SelectObject(m_oldBitmap);
if (m_bitmap != NULL) delete m_bitmap;
}
CMemDC* operator->() {
return this;
}
};


OnDraw(){
CRect rect;
GetClientRect(&rect);
CMemDC dc(pDC, rect);
dc->FillRect(rect, CBrush::FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH)));

// TODO: add draw code for native data here
}

+ Recent posts