성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] Roll A Lisp In C - Reading ; https...
[정성태] Java - How to use the Foreign Funct...
[정성태] 제가 큰 실수를 했군요. ^^; Delegate를 통한 Bein...
[정성태] Working with Rust Libraries from C#...
[정성태] Detecting blocking calls using asyn...
[정성태] 아쉽게도, 커뮤니티는 아니고 개인 블로그입니다. ^^
[정성태] 질문이 잘 이해가 안 됩니다. 우선, 해당 소스코드에서 ILis...
[양승조
] var대신 dinamic으로 선언해서 해결은 했습니다. 맞는 해...
[양승조
] 또 막혔습니다. ㅠㅠ var list = props[i].Ge...
[양승조
] 아. 감사합니다. 어제는 안됐던것 같은데....정신을 차려야겠네...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>서로 다른 프로세스에서 WM_DROPFILES 메시지를 전송하는 방법</h1> <p> 아래의 답변을 하면서,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > drag&drop 관련해서 문의 드립니다. ; <a target='tab' href='http://www.sysnet.pe.kr/3/0/4756'>http://www.sysnet.pe.kr/3/0/4756</a> </pre> <br /> 테스트하다가 알게 된 사실을 하나 공유합니다. ^^<br /> <br /> OLE Drag&Drop이 아닌, 예전의 WM_DROPFILES Win32 윈도우 메시지를 이용해 (예를 들어 탐색기 같은) 외부 응용 프로그램에서 끌어다 놓기 했을 때 그 정보를 다음과 같이 받아올 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { // ...[생략]... <span style='color: blue; font-weight: bold'>DragAcceptFiles(hWnd, TRUE);</span> // ...[생략]... return TRUE; } LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { // ...[생략]... case WM_DROPFILES: { <span style='color: blue; font-weight: bold'>int fileCount = DragQueryFile((HDROP)wParam, -1, nullptr, 0);</span> DWORD dwError = ::GetLastError(); DragFinish((HDROP)wParam); char buf[1024] = { 0 }; if (fileCount != 0) { sprintf(buf, "FileCount: %d", fileCount); } else { sprintf(buf, "Error: %d", dwError); } MessageBoxA(nullptr, buf, nullptr, MB_OK); } break; // ...[생략]... } return 0; } </pre> <br /> 실제로 위와 같이 Win32 프로그램을 만든 후 윈도우 탐색기에서 파일을 끌어다 놓으면 DragQueryFile의 호출 결과로 1이라는 결과가 나옵니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> WM_DROPFILES가 Win32 Message이다 보니, 이를 SendMessage로 보내는 것도 가능합니다. 이에 대해서는 웹상의 많은 자료들이 다음과 같은 코드로 알려주고 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > char filename[] = "c:\\temp\\test.wav"; POINT point; point.x = 0; point.y = 0; int cbBuffer = sizeof(DROPFILES) + strlen(filename) + 2; if (HGLOBAL hGlobal = GlobalAlloc(GHND | GMEM_SHARE | GMEM_ZEROINIT, cbBuffer)) { DROPFILES * df = (DROPFILES *)GlobalLock(hGlobal); df->pFiles = sizeof(DROPFILES); df->pt = point; df->fNC = FALSE; df->fWide = FALSE; strcpy(reinterpret_cast<char *>(df + 1), filename); GlobalUnlock(hGlobal); <span style='color: blue; font-weight: bold'>SendMessage(hWnd, WM_DROPFILES, (WPARAM)hGlobal, 0);</span> GlobalFree(hGlobal); } </pre> <br /> 실제로 위와 같은 코드는 같은 EXE 프로세스 내에서 SendMessage를 한 경우에는 잘 동작합니다. 하지만, 다른 EXE 프로세스로 보낼 때는 상대 측의 WM_DROPFILES에 있는 DragQueryFile 함수가 0을 반환하고 오류 코드는 6 (The handle is invalid.)으로 나옵니다.<br /> <br /> 왜냐하면, 윈도우 시스템은 WM_DROPFILES 메시지의 경우 자동으로 마샬링을 하지는 않기 때문입니다. 설령, 마샬링을 한다 해도 현재의 WM_DROPFILES 처리 방식에서 보자면 넘어온 HGLOBAL 주소 값이 프로세스 간에 마샬링 된 주소와 동일할 것이라는 보장이 없으므로 역시 오류가 발생하는 것은 마찬가지입니다.<br /> <br /> 그럼, 도대체 어떤 수수께끼가 있는 것일까요?<br /> <br /> 이에 대해서는 WM_DROPFILES를 허용하기 위해 <a target='tab' href='https://www.sysnet.pe.kr/2/0/12633'>UAC의 UIPI 보안</a>을 설정하는 코드에서 힌트를 얻을 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > [Tip] UAC 때문에 WM_DROPFILES 메시지를 받을수 없는 경우에 대한 처리 ; <a target='tab' href='http://www.tipssoft.com/bulletin/board.php?bo_table=FAQ&wr_id=1571'>http://www.tipssoft.com/bulletin/board.php?bo_table=FAQ&wr_id=1571</a> </pre> <br /> 위의 글에 보면, WM_DROPFILES뿐만 아니라 WM_COPYGLOBALDATA도 Message Filter에 추가해야 하는 것을 알 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > ChangeWindowMessageFilter(WM_COPYGLOBALDATA, MSGFLT_ADD); ChangeWindowMessageFilter(WM_DROPFILES, MSGFLT_ADD); </pre> <br /> 유추가 되지요? ^^<br /> <br /> 즉, 탐색기에서 파일을 끌어다 놓으면 우선 HGLOBAL에 대한 데이터를 대상 프로세스에 WM_COPYGLOBALDATA를 이용해 복사한 후, 그 프로세스에서 새롭게 할당된 HGLOBAL 주소를 WM_DROPFILES에 넘기는 것으로 짐작할 수 있습니다.<br /> <br /> 문제는, WM_COPYGLOBALDATA 메시지의 사용법에 대한 공식 문서가 없다는 것입니다. <br /> <br /> 다행이라면, 검색해 보면 ^^ 사용 코드가 나옵니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > [ros-diffs] [jimtabor] 50047: [Win32k|User32] - Finish 50030 (work by Giannis), Now PostMessage passes all the correct data based on Get/PeekMessage. Example: Post A, Get/Peek A, Translate A, Dispatch A, shoul... ; <a target='tab' href='https://www.mail-archive.com/ros-diffs@reactos.org/msg09395.html'>https://www.mail-archive.com/ros-diffs@reactos.org/msg09395.html</a> </pre> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > + Ret = SendMessageA( hWnd, + WM_COPYGLOBALDATA, + (WPARAM)GlobalSize((HGLOBAL)wParam), // Zero if not a handle. + (LPARAM)wParam); // Send wParam as lParam. + + if ( Ret ) return NtUserPostMessage(hWnd, Msg, (WPARAM)Ret, lParam); </pre> <br /> 사용법이 정말 간단합니다. WM_COPYGLOBALDATA는 GlobalAlloc으로 전달받은 주소의 데이터를 대상 윈도우의 프로세스로 마샬링해주고, 그에 대한 새로운 EXE 프로세스 공간의 메모리 주소 값을 반환해줍니다.<br /> <br /> 이를 이용해 최종적으로 다음과 같이 EXE 간의 WM_DROPFILES 메시지 전송을 할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > char filename[] = "c:\\temp\\test.wav"; POINT point; point.x = 0; point.y = 0; HWND targetWindow = FindWindow(nullptr, L"...[yours]..."); int cbBuffer = sizeof(DROPFILES) + strlen(filename) + 2; if (HGLOBAL hGlobal = GlobalAlloc(GHND | GMEM_SHARE | GMEM_ZEROINIT, cbBuffer)) { DROPFILES * df = (DROPFILES *)GlobalLock(hGlobal); df->pFiles = sizeof(DROPFILES); df->pt = point; df->fNC = FALSE; df->fWide = FALSE; strcpy(reinterpret_cast<char *>(df + 1), filename); GlobalUnlock(hGlobal); // WM_COPYGLOBALDATA == 0x49 <span style='color: blue; font-weight: bold'>int result = SendMessage(targetWindow, 0x49, (WPARAM)cbBuffer, (LPARAM)hGlobal); SendMessage(targetWindow, WM_DROPFILES, (WPARAM)result, 0);</span> GlobalFree(hGlobal); } </pre> <br /> <a target='tab' href='http://www.sysnet.pe.kr/bbs/DownloadAttachment.aspx?fid=1056&boardid=331301885'>첨부한 파일은 다음과 같은 구성의 Win32Project1과 ConsoleApplication1 프로젝트를 포함</a>합니다.<br /> <br /> <ul> <li>Win32Project1: WM_DROPFILES 메시지를 받아 처리하는 프로그램</li> <li>ConsoleApplication1: SendMessage로 WM_DROPFILES 메시지를 Win32Project1로 전송하는 프로그램 (Help / About 메뉴로 SendMessage 코드 수행)</li> </ul> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
1721
(왼쪽의 숫자를 입력해야 합니다.)