. 검색결과창의 팝업 메뉴

검색 결과창에 좀 더 많은 기능을 구현하기 위해 팝업메뉴를 달아 보자. 팝업메뉴는 이미 리소스에 정의되어 있다.

메뉴에는 검색된 결과를 텍스트로 복사하거나 편집창으로 전송할 수 있는 기능들이 정의되어 있다. 당근의 검색결과창은 한 번에 하나의 검색결과만 출력할 수 있기 때문에 여러 개의 검색결과를 비교해보기가 어렵다. 검색결과를 텍스트로 뽑아낼 수 있으면 각각의 검색결과를 별도의 편집창에 열어 비교해보기 편리하고 검색결과 자체를 파일로 저장할 수 있을 것이다.

검색 결과창의 WM_CONTEXTMENU에서 팝업메뉴를 출력하고 WM_COMMAND에서 메뉴항목이 선택되었을 때의 명령을 처리한다. 마우스 오른쪽 버튼 대신 <Shift+F10>으로 팝업메뉴를 호출했을 때는 20,20 좌표에 팝업메뉴가 열리도록 하였다.

 

LRESULT CALLBACK DGOutputProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)

{

     HMENU hMenu, hPopup;

     int idx;

 

     switch(iMessage) {

          ....

     case WM_CONTEXTMENU:

          LVHITTESTINFO pinfo;

          POINT pt;

          hMenu=LoadMenu(g_hInst, MAKEINTRESOURCE(IDR_POPUP));

          hPopup=GetSubMenu(hMenu, 0);

 

          pinfo.pt.x=LOWORD(lParam);

          pinfo.pt.y=HIWORD(lParam);

          ScreenToClient(hList,&pinfo.pt);

          ListView_HitTest(hList,&pinfo);

          if (pinfo.iItem == -1) {

              EnableMenuItem(hPopup,IDM_OUTPUT_GO,MF_BYCOMMAND | MF_GRAYED);

          }

 

          if (LOWORD(lParam)==65535) {

              pt.x=20;

              pt.y=20;

              ClientToScreen(hWnd,&pt);

              lParam=MAKELPARAM(pt.x,pt.y);

          }

          TrackPopupMenu(hPopup, TPM_LEFTALIGN, LOWORD(lParam), HIWORD(lParam),

              0, hWnd, NULL);

          DestroyMenu(hMenu);

          return 0;

     case WM_COMMAND:

          switch(LOWORD(wParam)) {

          case IDM_OUTPUT_GO:

              idx=ListView_GetNextItem(hList,-1,LVNI_ALL | LVNI_SELECTED);

              if (idx != -1) {

                   OpenFileFromOutput(idx);

              }

              break;

          case IDM_OUTPUT_COPY:

              CopyOutputToText();

              break;

          case IDM_OUTPUT_SEND:

              SendOutputToWindow();

              break;

          case IDM_OUTPUT_SENDNEW:

              New();

              SendOutputToWindow();

              break;

          case IDM_OUTPUT_CLOSE:

              Option.bShowOutput=FALSE;

              Relayout();

              break;

          }

          return 0;

     ....

 

검색 결과창 닫기는 bShowOutput FALSE로 만든 후 Relayout만 호출하면 된다. 검색된 파일로 가기는 앞에서 이미 작성해두었고 나머지 기능들은 별도의 함수를 만들도록 한다. 검색결과를 텍스트로 복사하는 함수와 편집창으로 전송하는 함수, 그리고 리스트 뷰 컨트롤에서 텍스트를 추출하는 함수를 작성한다.

 

void CopyOutputToText()

{

     HGLOBAL hmem;

     TCHAR *ptr;

     TCHAR *buf;

 

     ExtractOutputToText(buf);

     hmem=GlobalAlloc(GHND, strlen(buf)+1);

     ptr=(TCHAR *)GlobalLock(hmem);

     memcpy(ptr,buf,lstrlen(buf)+1);

     GlobalUnlock(hmem);

     if (OpenClipboard(g_hFrameWnd)) {

          EmptyClipboard();

          SetClipboardData(CF_TEXT,hmem);

          CloseClipboard();

     }

     free(buf);

}

 

void SendOutputToWindow()

{

     TCHAR *buf;

     HWND hActive;

     SInfo *pSi;

 

     hActive=(HWND)SendMessage(g_hMDIClient,WM_MDIGETACTIVE,0,NULL);

     if (hActive==NULL)

          return;

 

     pSi=(SInfo *)GetWindowLong(hActive,0);

     ExtractOutputToText(buf);

     pSi->Ae.Insert(pSi->Ae.GetOffset(),buf);

     pSi->Ae.Invalidate(-1);

     free(buf);

}

 

void ExtractOutputToText(TCHAR *&buf)

{

     int buflen;

     int idx,count;

     TCHAR Num[16];

     TCHAR Path[MAX_PATH];

     TCHAR Text[4096];

 

     buflen=10000;

     buf=(TCHAR *)malloc(buflen);

     buf[0]=0;

 

     count=ListView_GetItemCount(hList);

     for (idx=0;idx<count;idx++) {

          if (buflen-lstrlen(buf) < 5000) {

              buflen+=10000;

              buf=(TCHAR *)realloc(buf,buflen);

          }

          ListView_GetItemText(hList,idx,0,Num,16);

          lstrcat(buf,Num);

          lstrcat(buf," : ");

          ListView_GetItemText(hList,idx,1,Path,MAX_PATH);

          lstrcat(buf,Path);

          lstrcat(buf," ==> ");

          memset(Text,0,4096);

          ListView_GetItemText(hList,idx,2,Text,4000);

          lstrcat(buf,Text);

          lstrcat(buf,"\r\n");

     }

}

 

리스트 뷰의 검색결과를 텍스트로 뽑아내는 것은 아주 쉽다. 각 줄의 컬럼에 있는 텍스트를 추출하여 연결하면 하나의 검색결과를 구할 수 있으며 각 줄에 대한 검색결과 뒤에 개행코드를 붙여 연결하기만 하면 된다. 텍스트의 길이를 미리 알 수 없기 때문에 버퍼를 동적으로 관리해야 한다. CopyOutputToText는 이렇게 추출된 문자열을 클립보드로 전송하며 SendOutputToWindow는 활성창으로 전송한다.