페이지

2010년 3월 22일 월요일

[두루에디트 제작기] 쓰레드 검색처리시 입력장치공유

메인창 메인프로세스 쓰레드와는 별도로 생성하여 돌리는 검색쓰레드 내부이다.
쓰레드는 윈도우를 생성한 메인쓰레드의 키보드나 Focus정보를 공유못하도록되어있다.
GetFocus등이 null이 리턴된다. 아래는 공유하는 코드이다.

DWORD DEFinder::FindAllProc(LPVOID pParam)
{
BOOL flag = FALSE;
DEFinder *pRoot = reinterpret_cast (pParam);
DEMainWnd *pMainWnd = (DEMainWnd *)KFCGetMainWnd();
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
pRoot->m_threadreqcnt = 1;
#ifdef DE_USE_THREADSAFE_GETFOCUS_INPUT
//쓰레드로 돌릴때 GetFocus등이 NULL이 리턴된다.쓰레드별로 독립적으로 관리되기 때문에
//GetFocus등이 NULL을 돌려주기 때문에 편집창의 캐럿위치가 제대로 반영이 안된다.
//따라서 쓰레드를 메인프로세스의 쓰레드로 ATTACH하여 메세지큐를 공유하도록 한다.

DWORD dwProcessId = 0;
DWORD dwMainThreadId= GetWindowThreadProcessId(pMainWnd->GetSafeHwnd(),&dwProcessId);
DWORD dwMyThreadId = GetCurrentThreadId();

BOOL at = AttachThreadInput(dwMainThreadId,dwMyThreadId,TRUE);
#endif
while(1){
pRoot->m_faparam.bStop = 0;
if(pRoot->m_faparam.which == FW_FIND pRoot->m_faparam.which == FW_REPLACE){
pRoot->FindNext(&pRoot->m_faparam);//매번 처음 검색
}
else
pRoot->FindAll(&pRoot->m_faparam);
if(pRoot->m_faparam.bStop)
TRACELOG("취소됨\n");
pRoot->m_threadreqcnt--;
if(pRoot->m_threadreqcnt <= 0) break; } pRoot->m_hfthread = NULL;
TRACELOG("쓰레드종료\n");
if(pRoot->m_faparam.which != FW_FIND && pRoot->m_faparam.which != FW_REPLACE){
if(pMainWnd->m_wndOutputBar.IsWindow())
ListBox_AddString(pMainWnd->m_wndOutputBar.m_hListBox,"검색 쓰레드 종료");
}
#ifdef DE_USE_THREADSAFE_GETFOCUS_INPUT
at = AttachThreadInput(dwMainThreadId,dwMyThreadId,FALSE);
#endif
return 0;
}

2010년 3월 14일 일요일

[두루에디트 제작기] 정규식(Regular Expression) 검색 구현


[작성중인 두루에디트]


[작성중인 정규식 명령메뉴]


정규식 검색을 구현했다..ui메뉴 작성중...


정규식은 동시에 여러 단어 검색할때 유용하다.


예를 들어 ET 가 들어가는 단어와 EX가 들어가는 단어를 모조리 한번에 찾고자 할때


E[A-Z] 식으로 사용하며 ETT도 찾고 EXT도 찾으려면 정규식 검색체크박스를 체크하고


E[A-Z]+ 나 E[A-Z]*를 사용하면 된다.^^ 단,파일이 크고 식이 복잡할수록 검색시간이 다소 걸린다.


정규식은 DERegExp 클래스 하나로 구현되었다.





정규식 이외에 기본 검색기능은,


vc++ 것과 마찬가지로 빠른찾기,빠른바꾸기,파일에서 찾기,파일에서 바꾸기 등 4가지 기능 화면이 있고 작게로는 다음찾기,다음바꾸기,모두찾기,모두바꾸기,파일 건너뛰기,파일형식만 찾기(디렉토리 목록에서 *.c나 *.txt 파일만 검색하는 기능) 등이다.


검색대상으로는 현재문서,모든 열린문서,지정된 폴더등 3가지이다.나중에 블럭선택한 내용을 추가해야겠다.


파일찾기나 바꾸기는 우선,열려있는 문서를 상대로 해당경로에 있으면 우선 검색대상에 포함한다. 또,파일을 찾아가며 검색어가 포함된 파일이 열려있으면 이때는 파일을 메모리에서 검색하는게 아니고 열려있는 문서의 버퍼내용으로 검색한다.(수정되어 있는 내용이 우선시)


또, 문서를 대상으로 다음찾기(바꾸기) 등은 버튼을 누를때마다 문서를 현재 캐럿(커서)위치서 부터 한스텝씩 next,,next해가며 검색하면되지만 파일을 대상으로 다음찾기는,하위폴더까지 모조리 탐색해야 하므로 시간소요가 많은점을 고려하여 최적의 퍼포먼스를 나게했다.^^


우선 해당 검색 파일형식의 파일들만 하위폴더까지 모조리 검색하여 파일목록을 쌓아놓는게 아니고(이렇게 하면 파일양이 많을때 방대한 메모리사용...의 문제점,또 버튼 누른 즉시 검색이 안되고 한동안 파일만 찾고 있을 것이다) 해당 파일형식(예를들어,*.txt;*.cpp를 지정했다하면)


이 있는 폴더만 조사하여 내부 vector 리스트로 만든다음, 첫번째 리스트 index를 상대로


FindFirstFile를 수행하고 FindNextFile 을 계속해나가며 내용이 있는 파일을 만나면 멈춘다.


그리고 이 HANDLE을 보관하고 있다가, 다음번에 "다음찾기" 가 눌리면 FindNextFile(저장한 핸들) 로 계속 검색한다. 해당 폴더에 파일이 없으면, 다음 리스트의 index++ 하여 이런식으로 검색해 나간다.


그리고,파일검색중 이미 열려있어서 문서로 검색해놓았는데 사용자가 중간에 닫은 경우,


다시 검색되도록 열려있는 문서창의 핸들 HWND는 wndlist 에 push_back 해놓는다 ^^


상세검색 옵션으로는, 대소문자 구분,단어만검색,위로검색,정규식사용,하위폴더포함,숨김파일포함등이 있고, 이 모든것은 Thread 로 처리된다.


이 검색기능은 DEFinder 라는 검색관리자 클래스가 홀로 담당한다.

2010년 3월 10일 수요일

[두루에디트 제작기] 검색용 드롭다운 콤보박스 동적생성

콤보박스를 동적생성할때는 WS_VSCROLL 가 있어야 리스트드롭박스에 테두리가 생긴다.
또,Create 시 height를 주는만큼 리스트드롭박스 크기가 결정된다.
생성시 높이크기를 0으로 주고 나중에 아무리해봐야 안된다.^^

[두루에디트 제작기] Visual Leak Detector - vld의 Bug

#ifdef _DEBUG
//#include "vld.h" //Virtual Memory Leak Debug Library 파일공통대화상자(열기,저장)가 안열리고 멈춰있는 버그있다.
#endif

이런젠장,난 또 메모리 폴트난줄알고 한참 헤멧네..

vc++ 2008 Team suite SP1 ,windows7(x64), compile 32bit program with SDK.

VLD Library cause program halt when call GetSaveFileName(), GetOpenFileName().

I guess it hooks and has somebug with common dialog.
Visual Leak Detector - Enhanced Memory Leak Detection for Visual ...

2010년 3월 7일 일요일

[두루에디트 제작기] Kill or Prevent Beep in Edit Control ,Editctrl 에디트 컨트롤 비프음 없애기

Subclass your Edit control,
and processing WM_CHAR message, return 1 to avoid default window routine;

e.g) sample of duruedit source

BOOL SubClassEditCtrl::OnChar(UINT nChar,UINT nRepCnt,UINT nFlags)
{
//if(m_nLastChar == 0)
// SetWindowText(m_hWnd,"");
//m_nLastChar = nChar;
if (nChar == VK_TAB nChar == VK_RETURN nChar == VK_ESCAPE)
{
//비프음을 없앤다
return 1;
}
return 0;//pass to default proc
}




또는 PreTranslateMessage에서 해당 다이얼로그나 컨트롤을 탑재한 윈도우가 떠 있는 경우(프레임과는 별도로),포커스를 받기원하고 비프음을 제거하려면 기본 로직을 타지않도록 return TRUE 하면 된다.

아래는 KFC 라이브러리로 개발중인 두루에디터의 실례이다.

여기서 KFCLib 의 경우의 PreTranslateMessage함수는 sdk로 따지자면 GetMessage 루프에서 검사해오는 루틴에 끼어있는것이다.

만일,MFC는 같은 이름의 함수부분에서 처리하고 SDK 라면 WinMain의 GetMessage,PeekMessage 부분에서 검사하면 마찬가지 효과이다.

BOOL DEMainWnd::PreTranslateMessage(MSG* pMsg)
{
//2010.0226 krkim 검색창 에디터에 copy/paste가 잘 안듣는 문제해결
//키보드 엑셀레이터를 못타도록 하여 편집창이 처리하지 않고 검색창 에디터가
//처리하도록 내버려 둔다.
if (::IsWindow(m_dlgFinder.GetSafeHwnd()) && IsDialogMessage(m_dlgFinder.GetSafeHwnd(),pMsg))
return TRUE;//FALSE TO Translate

if(m_wndFindBar.PreTranslateMessage(pMsg))//FindBar 콤보박스의 에디터에 키입력 메세지를 날리기 위해..
return TRUE;

//TRACELOG("hWnd = %X,nChar = %X bCtrl = %d m_wndFindBar.m_hEditBox = %X,hActiveEdit=%X\n",
// pMsg->hwnd,nChar,bControl,m_wndFindBar.m_hEditBox,hActiveEdit);
if (::IsWindow(m_wndFindBar.GetSafeHwnd()) && IsDialogMessage(m_wndFindBar.GetSafeHwnd(),pMsg))
return TRUE;

return KFCMDIFrame::PreTranslateMessage(pMsg);
}


예로,본인이 WTL + SDK + MFC 의 장점만을 따와 자작한 KFC 라이브러리는 ,실행속도와 파일크기는 MFC > WTL > SDK 순으로 느린 반면에, KFC 라이브러리는 WTL과 SDK의 거의 중간급에서의 퍼포먼스를 나타내고 속도는 빠른 반면 개발이난해한 SDK의 단점과 WTL 코드의 어지러움등을 모두 한방에 해결하기 위해 만든 C++클래스 계층구조 형태로 자체제작한 윈도우즈 플랫폼 개발 라이브러리이다.

현재 버전은 즉,
Window 클래스로는
KFCApp
KFCWnd - KFCDlg
- KFCFrame - KFCMDIFrame
- KFCMDIChild , KFCMDIWnd
- KFCToolbar
- KFCPropPage,KFCPropSheet
- KFCScrollBar
- KFCButton - KFCSkinButton
- KFCStatic
- KFCLabel
- KFCTabCtrl - KFCMDITabCtrl
- KFCToolTop
- KFCHotKeyCtrl

DC 관련 클래스로는,
KFCBitmap
KFCDC
KFCPaintDC
KFCWindowDC
등으로 구성되어져 있다.
현재 버전만으로 MDI,SDI,Dialog 기반등 모든 응용프로그램의 제작이 쉽게 가능하다.

예) 다이얼로그 호출법

KFCDlg dlg(IDD_MYDLG,m_hWnd);
int flag = dlg.DoModal();

형태로 SDK는 CreateDialog 등 복잡한 함수를 매번 나열해야 하지만,
쉽게 WTL이나 MFC의 것과 유사하게 코드가 간편하다.

나머지, 없는 클래스는, 그때그때 필요에 의해 작성하여 새롭게 추가할 것이다.
(몇년동안 그렇게 해왔고..실제 본인프로젝트에 강력하게 쓰고있고 강력함을 스스로 느낀다.^^)

KFC의 메세지 펌핑 루틴의 소스코드는 다음과 같다.
이라이브러리는 여유와 기회가 되면 오픈소스 차원에서 별도의 웹공간에 풀소스 공개할 생각이다..

int KFCApp::MessageLoop()
{
// The main message loop
int status;
MSG msg;
if(m_bInit == FALSE){
ExitInstance();
return -2;
}

//다이얼로그는 InitInstance()에서 DoModal() 호출할것!
//In Dialog Top Window,call DoModal() first in InitInstance().

//CHAR classname[80] = {0,};
//if(GetClassName(m_pMainWnd->m_hWnd,classname,sizeof(classname)) > 0)
// if(!stricmp(classname,"#32770"))
// return -2;
if(!m_pMainWnd){
throw KFCException("Warning! Please Indicate m_pMainWnd in InitInstance\n");
ExitInstance();
return -2;
}
BOOL bIdle = true;
for(;;)
{
while(bIdle && !::PeekMessage(&msg,NULL,0,0,PM_NOREMOVE))
{
if(!OnIdle())
bIdle = false;
}
status = GetMessage(&msg, 0, 0, 0);
if(status == -1)//error occured ,don't process
continue;
if(status == 0)//met WM_QUIT
break;
Run();
if(!PreTranslateMessage(&msg))
{
TranslateMessage (&msg);
DispatchMessage (&msg);
}
bIdle = IsIdleMessage(&msg);
}
ExitInstance();
return msg.wParam;
}

2010년 3월 2일 화요일

하나포스가 문닫는구나

블로그글들을 어찌할꼬..

VS 2008 RTM C++ Incremental Linker 작동 오류

FIX: LNK1000 error when incrementally linking a Visual C++ Project

https://connect.microsoft.com/VisualStudio/Downloads/DownloadDetails.aspx?DownloadID=11399

visual studio 2008 서비스팩 1 을 설치하면 해결됨.