'3. Implementation/Windows API'에 해당되는 글 40건

  1. 2011.08.16 GetAsyncKeyState 사용법
  2. 2010.12.17 Execute Applications on Remote Systems - PsEXEC
  3. 2010.12.08 What is the difference between HINSTANCE and HMODULE?
  4. 2010.10.22 Create a movie from an HBitmap
  5. 2010.04.21 Download a File Using URLDownloadToCacheFile
  6. 2010.03.08 OutputDebugString 캡처하기 - DebugView 를 만들어보자
  7. 2010.02.05 Video For Windows Single-Frame Capture Class Without MFC
  8. 2009.11.27 Execute Applications on Remote Systems
  9. 2009.10.12 PostThreadMessage 함수
  10. 2009.10.12 Window 에서 Owner 관계
  11. 2009.10.11 SignalObjectAndWait 함수
  12. 2009.10.11 Sleep 과 SwichToThread 함수
  13. 2009.10.11 WaitForInputIdle 함수 1
  14. 2009.08.28 클립보드(Clipboard)에 비트맵 저장 & 로드
  15. 2009.07.04 EXE 안에 외부의 데이터파일 저장하기
  16. 2009.07.03 간단하게 취소 기능 구현하기
  17. 2009.04.09 WPARAM 과 LPARAM
  18. 2009.03.06 MsgWaitForMultipleObjects and the queue state
  19. 2008.12.10 Obtaining Directory Change Notifications
  20. 2008.12.10 소멸자를 이용한 뮤텍스 권한 소유 및 해제
2011. 8. 16. 23:13

GetAsyncKeyState 사용법

키의 다운 여부를 체크하기 위한 GetAsyncKeyState 함수가 있습니다. 이에 대한 사용법은 다음과 같습니다.

if (GetAsyncKeyState(VK_SHIFT) & 0x8000)
{
   // The key is currently down
}


unsigned char KeyStates[256];
GetKeyboardState(KeyStates);

for (int i = 0; i < 256; i++)
{
      if (KeyStates[i] & 0x8000)
      {
            // The keyboard key that 'i' represents is currently held down.
      }
}


출처: http://cboard.cprogramming.com/cplusplus-programming/112970-getasynckeystate-key-pressed.html
2010. 12. 17. 07:20

Execute Applications on Remote Systems - PsEXEC

출처: http://www.codeguru.com/cpp/i-n/network/remoteinvocation/article.php/c5433


Environment: NT4 SP6, Win 2000 SP1, Visual C++ 6.0

Overview

This program allows you to execute applications on remote systems without installing any client software. You can start a command prompt or just execute a command or exe  on a remote machine. The only restriction is you must be an administrator :(

Everybody knows the cool tools from Sysinternals (www.sysinternals.com). One of my favorites are PSEXEC, PSKILL and PSLIST,... :)
I was always wonder how they could query every kind of information or execute commands on a remote machine without installing any client software.

Features

  • With this program you can run as many remote commands on the remote machine as you want.  (PSEXEC supports only one remote command on the remote machine at the same time)
  • You can execute internal commands (dir,..) directly.
        xCmd.exe \\remote dir
  • You can start a light "telnet" connection with a remote machine without any telnet server 
        xCmd.exe \\remote cmd

Usage

xCmd v1.0 for NT4/2000 - executes commands remotely
Freeware! 2001 Zoltan Csizmadia, zoltan_csizmadia@yahoo.com

Usage: xCmd.exe \\computer [options] command/exe arguments

Options:
    /D:directory         Set working directory
                         Default: Remote "%SystemRoot%\System32"
    /IDLE                Idle priority class
    /NORMAL              Normal priority class
    /HIGH                High priority class
    /REALTIME            Realtime priority class
    /C                   Copy the specified program to the remote machine's
                         "%SystemRoot%\System32" directory
                         Commands's exe file must be absolute to local machine
    /USER:user           User for remote connection
    /PWD:{password|*}    Password for remote connection
    /NOWAIT              Don't wait for remote process to terminate

Examples:
    xCmd.exe \\remote cmd
    xCmd.exe \\remote /user:administrator dir c:\ 
    xCmd.exe \\remote /user:somebody /pwd:* /d:d:\ test1.exe /p1 /p2 
    xCmd.exe \\remote /c /user:somebody /pwd:* /d:d:\ test2.exe /whatever

- Input is passed to remote machine when you press the ENTER.
- Ctrl-C terminates the remote process
- Command and file path arguments have to be absolute to remote machine
  If you are using /c option, command exe file path must be absolute to
  local machine, but the arguments must be absolute to remote machine

How does it work?

  1. The xCmd.exe is console application and when you start it, the program will extract a xCmdSvc.exe from its resources.
  2. xCmd.exe creates a service on the remote machine (that's the reason, you must be an administrator
  3. xCmd.exe starts the remote service (#2)
  4. xCmd.exe and xCmdSvc.exe will communicate via named pipes
  5. xCmd.exe send a packet to the service what to execute
  6. xCmdSvc.exe starts the command and redirect stdout, stderr, stdin to 3 named pipes. 
  7. xCmd.exe listens these 3 named pipes (#6), redirect them to its stdout, stderr, stdin

Notes

The executable is compiled and linked on Windows 2000 SP1, VC++ 6.0 SP4 and in multithreaded DLL mode.
So if you get some errors, rebuild your executable from the source (xCmd.dsw).


2010. 12. 8. 04:04

What is the difference between HINSTANCE and HMODULE?

They mean the same thing today, but at one time they were quite different.

It all comes from 16-bit Windows.

In those days, a "module" represented a file on disk that had been loaded into memory, and the module "handle" was a handle to a data structure that described the parts of the file, where they come from, and where they had been loaded into memory (if at all). On the other hand an "instance" represented a "set of variables".

One analogy that might (or might not) make sense is that a "module" is like the code for a C++ class - it describes how to construct an object, it implements the methods, it describes how the objects of the class behave. On the other hand, an "instance" is like a C++ object that belongs to that class - it describes the state of a particular instance of that object.

In C# terms, a "module" is like a "type" and an instance is like an "object". (Except that modules don't have things like "static members", but it was a weak analogy anyway.)

Here's a diagram. (Recall that we discussed 16-bit HRSRC in a previous entry.)

USER32 HMODULE USER32 HINSTANCE
code segment descriptor USER32 code... USER32 data...
code segment descriptor (not in memory)
code segment descriptor USER32 code...
data segment descriptor
HRSRC (not in memory)
HRSRC USER32 resource...
HRSRC (not in memory)
exports table

In 16-bit Windows, all programs ran in a single address space, and if a DLL was used by five programs, it was loaded only once into memory. In particular, it got only one copy of its data segment. (In C++/C# terms, a DLL is like a "singleton class".)

That's right, DLLs were system-global rather than per-process. The DLL did not get a separate copy of its data for each process that loaded it. If that was important to your DLL, you had to keep track of it yourself.

In geek terms, there was only one "instance" of a DLL in the system.

On the other hand, if you ran two copies of Notepad, each one got its separate set of variables - there were two "instances".

NOTEPAD HMODULE HINSTANCE
code segment descriptor NOTEPAD code... NOTEPAD data...
code segment descriptor (not in memory)
data segment descriptor HINSTANCE
HRSRC (not in memory) NOTEPAD data...
HRSRC NOTEPAD resource...

Both running copies of Notepad shared the NOTEPAD module (so the code and resources were shared), but each had its own copy of its variables (separate data segment). There were two "instances" of Notepad.

The "instance" handles in the above diagrams are the data segments.

Programs are identified by their the instance handle. You can't use the module handle, because the two copies of Notepad have the same module handle (since the same code is running in each). The thing that makes them different is that each has its own set of global variables.

This is why the WinExec and ShellExecute functions return HINSTANCE: They are holdovers from 16-bit Windows, where HINSTANCEs were the way to identify running programs.

The method by which code receives its HINSTANCE (i.e., knows where its global variables are) I will leave for a future article. It is somehow related to the now-obsolete MakeProcInstance function.

When it came to design Win32, the question then arose, "What do we do with HINSTANCE and HMODULE for Win32?" Since programs ran in separate address spaces, you didn't have instance handles visible across process boundaries. So the designers took the only thing they had: The base address of the module. This was analogous to the HMODULE, since the file header describes the contents of the file and its structure. And it was also analogous to the HINSTANCE, since the data was kept in the data segment, which was mapped into the process directly.

So in Win32, HINSTANCE and HMODULE are both just the base address of the module.

Tomorrow, I'll talk about that mysterious hinstPrev parameter to WinMain.


원문: http://blogs.msdn.com/b/oldnewthing/archive/2004/06/14/155107.aspx

2010. 10. 22. 06:59

Create a movie from an HBitmap

이미지로부터 동영상 생성을 간편하게 해주는 유틸 클래스.
Windows Application 자동화 시에 적용하였음.

2010. 4. 21. 22:57

Download a File Using URLDownloadToCacheFile

You can use WinInet to download a file from the Internet. But the easier way is to use the ::URLDownloadToCacheFile() or ::URLDownloadToFile() functions. The URL functions combine the capabilities of asynchronous monikers and URL monikers into easy-to-use functions. By using these functions, you do not have to worry about the protocols used to transfer the files, such as HTTP, FTP. In the simplest case, all you have to do is to pass them the URL. ::URLDownloadToCacheFile() downloads data into the Internet cache and returns the file name of the cache location for retrieving the bits. ::URLDownloadToFile() downloads bits from the Internet and saves them to a file. However, they are blocking functions. Even though the data is downloaded asynchronously the functions do not return until all the data is downloaded. You can choose to be notified of progress through a notification callback.

......

http://www.codeproject.com/KB/IP/urlfile.aspx
2010. 3. 8. 23:10

OutputDebugString 캡처하기 - DebugView 를 만들어보자

디버깅시 유용한 DebugView 는 OutputDebugString 을 캡처하여 보여주는 역할을 한다. 이와 동일한 기능을 구현하는 코드 예는 다음과 같다.

 

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

    struct DbWinBuffer

    {

        DWORD dwProcessId;

        char data[4096 - sizeof(DWORD)];

    };

 

    DbWinBuffer* dbBuffer;

 

    HANDLE hAckEvent;

    HANDLE hEvent;

    HANDLE hSharedFile;

 

    SECURITY_DESCRIPTOR sd;

    SECURITY_ATTRIBUTES sa;

 

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

 

    sa.nLength = sizeof(SECURITY_ATTRIBUTES);

    sa.bInheritHandle = true;

    sa.lpSecurityDescriptor = &sd;

 

    if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION))

    {

        printf("ERROR: InitializeSecurityDescriptor\\n");

        return 1;

    }

 

    if (!SetSecurityDescriptorDacl(&sd, true, 0, false))

    {

        printf("ERROR: SetSecurityDescriptorDacl\n");

        return 1;

    }

 

    hAckEvent = CreateEvent(&sa, false, false, L"DBWIN_BUFFER_READY");

    if (!hAckEvent)

    {

        printf("ERROR: CreateEvent(\\"DBWIN_BUFFER_READY\\")\\n");

        return 1;

    }

 

    hEvent = CreateEvent(&sa, false, false, L"DBWIN_DATA_READY");

    if (!hEvent)

    {

        printf("ERROR: CreateEvent(\\"DBWIN_DATA_READY\\")\\n");

        return 1;

    }

 

    hSharedFile = CreateFileMapping((HANDLE)-1, &sa, PAGE_READWRITE, 0, 4096, L"DBWIN_BUFFER");

    if(!hSharedFile)

    {

        printf("ERROR: CreateFileMapping(\\"DBWIN_BUFFER\\")\\n");

        return 1;

    }

 

    dbBuffer = static_cast<DbWinBuffer*>(MapViewOfFile(hSharedFile, FILE_MAP_READ, 0, 0, 4096));

    if(!dbBuffer)

    {

        printf("ERROR: MapViewOfFile\\n");

        return 1;

    }

 

    SetEvent(hAckEvent);

 

    DWORD pid = GetCurrentProcessId();

    printf("Tracing PID: %dnn", pid);

 

    for(;;)

    {            

        DWORD ret = WaitForSingleObject(hEvent, INFINITE);

        if (ret == WAIT_FAILED)

        {

            printf("ERROR: WaitForSingleObject\\n");

            return 1;

        }

 

        if (dbBuffer->dwProcessId == pid)

        {

            printf("%s", dbBuffer->data);

        }

 

        SetEvent(hAckEvent);

    }

 




http://www.devmaster.net/forums/showthread.php?t=11229

2010. 2. 5. 06:49

Video For Windows Single-Frame Capture Class Without MFC

Codeguru 에 작성하기 까다로운 api 를 깔끔하게 클래스로 정리한 클래스가 있다. 테스트 해보니 웹캠 화면을 긇어와 화면에 뿌리는 거랑 캡처가 모두 잘 동작하는 것 같다.



출처 : http://www.codeguru.com/cpp/g-m/multimedia/video/article.php/c4723/
2009. 11. 27. 07:48

Execute Applications on Remote Systems

Zoltan Csizmadia (view profile)
April 13, 2001

.

Environment: NT4 SP6, Win 2000 SP1, Visual C++ 6.0

Overview

This program allows you to execute applications on remote systems without installing any client software. You can start a command prompt or just execute a command or exe  on a remote machine. The only restriction is you must be an administrator :(

Everybody knows the cool tools from Sysinternals (www.sysinternals.com). One of my favorites are PSEXEC, PSKILL and PSLIST,... :)
I was always wonder how they could query every kind of information or execute commands on a remote machine without installing any client software.

Features

Usage

xCmd v1.0 for NT4/2000 - executes commands remotely
Freeware! 2001 Zoltan Csizmadia, zoltan_csizmadia@yahoo.com

Usage: xCmd.exe \\computer [options] command/exe arguments

Options:
    /D:directory         Set working directory
                         Default: Remote "%SystemRoot%\System32"
    /IDLE                Idle priority class
    /NORMAL              Normal priority class
    /HIGH                High priority class
    /REALTIME            Realtime priority class
    /C                   Copy the specified program to the remote machine's
                         "%SystemRoot%\System32" directory
                         Commands's exe file must be absolute to local machine
    /USER:user           User for remote connection
    /PWD:{password|*}    Password for remote connection
    /NOWAIT              Don't wait for remote process to terminate

Examples:
    xCmd.exe \\remote cmd
    xCmd.exe \\remote /user:administrator dir c:\

    xCmd.exe \\remote /user:somebody /pwd:* /d:d:\ test1.exe /p1 /p2 
    xCmd.exe \\remote /c /user:somebody /pwd:* /d:d:\ test2.exe /whatever

- Input is passed to remote machine when you press the ENTER.
- Ctrl-C terminates the remote process
- Command and file path arguments have to be absolute to remote machine
  If you are using /c option, command exe file path must be absolute to
  local machine, but the arguments must be absolute to remote machine

How does it work?

  1. The xCmd.exe is console application and when you start it, the program will extract a xCmdSvc.exe from its resources.
  2. xCmd.exe creates a service on the remote machine (that's the reason, you must be an administrator
  3. xCmd.exe starts the remote service (#2)
  4. xCmd.exe and xCmdSvc.exe will communicate via named pipes
  5. xCmd.exe send a packet to the service what to execute
  6. xCmdSvc.exe starts the command and redirect stdout, stderr, stdin to 3 named pipes. 
  7. xCmd.exe listens these 3 named pipes (#6), redirect them to its stdout, stderr, stdin

Notes

The executable is compiled and linked on Windows 2000 SP1, VC++ 6.0 SP4 and in multithreaded DLL mode.
So if you get some errors, rebuild your executable from the source (xCmd.dsw).

From : http://www.codeguru.com/cpp/i-n/network/remoteinvocation/article.php/c5433/

윈도우즈 서비스를 원격에서 생성하고 실행시키는 방법을 이용한 아주 기발한 프로그램이다.

2009. 10. 12. 07:27

PostThreadMessage 함수

BOOL PostThreadMessage(DWORD idThread, UINT Msg, WPARAM wParam, LPARAM lParam);

다른 스레드의 메시지 큐에 메시지를 붙일 때 사용한다. 윈도우 핸들 대신 스레드의 ID 를 첫 번째 인수로 지정해 준다. 이때 이 메시지를 받을 스레드는 반드시 스레드 큐를 가지고 있어야 하는데 큐를 가지지 않는 Worker 스레드는 메시지를 받지 못한다.



[그림] PostMessage 와 SendMessage 가 메시지를 넣는 지점

참고 : Windows API 정복 - 김상형

2009. 10. 12. 07:10

Window 에서 Owner 관계

부모-자식 관계는 차일드 윈도우와 다른 윈도우와의 관계인데 비해 소유 관계는 오버랩드 팝업 윈도우간의 관계이다. 이때 다른 윈도우를 소유하는 윈도우를 소유자(Onwer)라고 하는데 오버랩드 윈도우나 팝업 윈도우만 소유자가 될 수 있다. 차일드 윈도우는 소유자가 될 수 없음은 물론이고 소유될  수도 없다.

소유된 윈도우는 소유자보다 항상 화면상의 위에 위치하며 소유자가 숨거나 파괴되면 같이 숨겨지고 파괴된다. 그러나 소유자의 이동은 소유된 윈도우에 아무런 영향도 주지 않는다. 윈도우간의 소유 관계는 CreateWindow 함수의 hwndParent 인수로 지정하는데 단 hwndParent 가 차일드 윈도우인 경우는 그 차일드가 소유자가 되지 않고 차일드를 소유하고 있는 윈도우가 소유자가 된다.

부모-자식 관계와, 소유자 관계의 또 다른 차이점은 부모는 실행중에 SetParent 함수로 변경할 수 있지만 소유 관계는 한번 설정되고 난 후에 변경할 수 없다는 점이다.

소유자 윈도우를 조사할 때는 GetWindow 함수를 사용한다.

HWND GetWindow(HWND hwnd, UINT uCmd);

이 함수는 hWnd 윈도우와 uCmd 관계에 있는 윈도우를 구해 주는데 GW_CHILD 이면 첫 번째 차일드 윈도우를 구해 주며 GW_OWNER 이면 소유자 윈도우를 구해준다.

출처 : Windows API 정복 - 김상형 저
2009. 10. 11. 21:58

SignalObjectAndWait 함수

DWORD SignalObjectAndwait(
HANDLE hObjectToSignal,
HANDLE hObjectToWaitOn,
HANDLE dwMilliseconds,
BOOL balertable);

특정 커널 오브젝트를 시그널 상태로 만들어주고, 이와는 또 다른 커널 오브젝트가 시그널 상태가 되기를 대기하는 긴으을 원자적으로 수행한다.

이 함수는 두 가지 이유로 인해 윈도우에 추가되었다.

첫째로, 개발자들은 특정 오브젝트를 시그널 상태로 만들어준 후 다른 오브젝트를 대기하는 식의 코드를 자주 작성하게 되는데, 단일 함수로 이와 같은 작업을 수행하게 되면 수행 시간을 절약해 주는 효과가 있다.

둘째로, SignalObjectAndWait 함수를 이용하면 이 함수를 호출한 스레드가 대기 상태에 있음을 보증할 수 있기 때문에 PulseEvent 와 같은 함수를 사용할 때 유용하게 활용될 수 있다. PulseEvent 는 특정 이벤트를 시그널 상태로 변경하였다가 그 즉시 논시그널 상태로 변경하게 되는데, 어떠한 이벤트를 대기 중인 스레드가 없다면 이벤트가 시그널되었는지를 감지할 수가 없다. 이전에 누군가가 다음과 같은 코드를 작성한 것을 본 적이 있다.

// 작업을 수행한다.
SetEvent(hEventWorkerThreadDone);
WaitForSingleObject(hEventMoreWorkToBeDone, INFINITE);
// 추가 작업을 수행한다.

워커스레드는 작업을 완료 후 SetEvent 를 호출하여 작업을 모두 마쳤음을 다른 스레드에게 알려준다. 다른 스레드는 아마도 다음과 같은 코드를 수행하고 있었을 것이다.

WaitForSingleObject (hEventWorkderThreadDone);
PulseEvent(hEventMoreWorkToBeDone);

워커스레드가 수행하고 있는 코드는 정상 동작하지 않을 수 있는 나쁜 구조다. 워커 스레드가 SetEvent 를 호출하면 다른 스레드가 즉각 깨어나서 PuseEvent 를 호출할 것이라 생각하겠지만 워커 스레드가 SetEvent 를 호출하고 hEventMoreWorkToBeDone 을 매개변수로 WaitForSingleObject 를 호출하기 전에 수행 흐름이 다른 스레드로 변경될 수 있다. 이렇게 되면 PuseEvent 가 ㅁ너저 호출되어 hEventMoreWorkToBeDone 에 대한 시그널 후 논시그널로의 변경작업이 먼저 수행되기 때문에 워커 스레드는 SignalObjectAndWait 함수를 이용하여 아래와 같이 재작성될 수 있다. 이 코드는 시그널 상태로의 변경과 대기를 원자적으로 수행하기 때문에 앞서와 같은 문제를 유발하지 않는다.

// 작업을 수행한다.
SignalObjectAndWait(hEventWorkerThreadDone, hEventMoreWorkToBeDone, INFINITE, FALSE);
// 추가 작업을 수행한다.

이 함수를 호출한 직후 다른 스레드로 제어가 넘어간다 해도 워커 스레드가 hEventMoreWorkToBeDone 이벤트를 대기 중인 것을 100% 보장할 수 있으므로 PulseEvent 호출을 통한 이벤트 상태 변경은 항상 감지될 수 있게 된다.

출처 : 제프리 리처의 Windows via C/C++
2009. 10. 11. 21:35

Sleep 과 SwichToThread 함수

void Sleep(DWORD dwMilliseconds);

일정 시간동안 자신을 스케줄하지 않도록 운영체제에게 명령을 내릴 수 있다.

  • Sleep 을 호출하면 스레드는 자발적으로 남은 타임 슬라이스를 포기한다.
  • Sleep 함수의 매개변수로 0을 전달할 수도 있다. 이렇게 하면 이 함수를 호출한 스레드가 남은 타임 슬라이스를 자발적으로 포기하여 시스템이 다른 스레들르 스케줄하게 한다. 그런데 시스템에 이 함수를 호출한 스레드와 우선순위가 같거나 그보다 높은 스레드 중에 스케줄 가능 스레드가 없는 경우 Sleep 함수를 호출한 스레드가 다시 스케줄 될 수도 있다.

BOOL SwitchToThread();

시스템은 일정 시간 동안 CPU 시간을 받지 못하여 수행되지 못하고 있던 스레드가 있는지 확인한다. 만일 그러한 스레드가 없다면 SwitchToThread 함수는 바로 반환되지만, 그러한 스레드가 존재한다면 SwitchToThread 는 해당 스레드를 스케줄 한다. 아마도 이러한 스레드는 SwitchToThread 함수를 호출한 스레드에 비해 낮은 우선순위를 가지고 있을 것이다. CPU 시간을 할당받은 스레드는 단일 퀀텀 시간 시간 동안만 수행되며, 이후 스케줄러는 이전과 동일하게 스케줄링을 수행한다.

이 함수를 이용하면 리소스를 소유하고 있는 낮은 우선순위의 스레드가 해당 리소스를 빨리 사용하고 반환할 수 있도록 해준다. SwitchToThread 를 호출하였을 때 수행할 스레드가 없다면 FALSE 를 반환하고, 그렇지 않은 경우 0이 아닌 값을 반환한다.

------

SwitchToThread 함수를 호출하는 것은 Sleep 함수를 호출할 때 인자로 0 밀리초의 타임아웃 값을 전달하는 것과 유사하다. 차이점이라면 SwitchToThread 의 경우 함수를 호출한 스레드보다 낮은 우선순위의 스레드들도 수행될 수 있다는 점일 것이다. Sleep 함수의 경우 설사 낮은 우선순위의 스레드들이 오랫동안 CPU 시간을 받지 못했다 하더라도 Sleep 함수를 호출한 스레드를 다시 스케줄링된다.

출처 : 제프리 리처의 Windows via c/c++
2009. 10. 11. 21:10

WaitForInputIdle 함수

DWORD WaitForInputIdle( HANDLE hProcess, DWORD dwMilliseconds );

hProcess 가 가리키는 프로세스의 첫 번째 윈도우를 생성한 스레드가 대기 상태가 될 때까지 WaitForInputIdle 함수를 호출한 스레드를 대기 상태로 유지한다. 이 함수는 Parent 프로세스가 CreateProcess 를 호출하여 차일드 프로세스의 생성을 요청한 후 차일드 프로세스가 완전히 초기화될 때까지 대기하도록 하고 싶은 경우에 유용하게 사용될 수 있다. 예를 들어 Parent 프로세스의 스레드가 차일드 프로세스가 생성한 윈도우 핸들을 얻어오려면 언제 차일드 프로세스가 초기화를 완료하고 더 이상 처리할 입력이 없는지를 알아야 한다. 이를 위해 Parent 프로세스는 CreateProcess 를 호출한 이후에 WaitforInputIdle 함수를 호출하면 된다.

WaitForInputIdle 함수는 애플리케이션에 키 입력을 전송해야 할 필요가 있을 경우에도 유용하게 사용될 수 있다. 애플리케이션의 주 윈도우에 다음과 같은 일련의 메시지들을 Post 해야 할 경우를 생각해 보자.

WM_KEYDOWN
VK_MENU 가상 키 값을 인자로 함
WM_KEYDOWN
VK_F 가상 키 값을 인자로 함
WM_KEYUP
VK_F 가상 키 값을 인자로 함
 WM_KEYUP VK_MENU 가상 키 값을 인자로 함
 WM_KEYDOWN VK_O 가상 키 값을 인자로 함
 WM_KEYUP VK_O 가상 키 값을 인자로 함


대부분의 영어 기반 애플리케이션에서는 Alt+F, O 를 누르면 파일 메뉴의 열기 명령이 수행된다. 이러한 명령을 수행하면 보통 열기 다이얼로그 박스가 나타나는데, 이를 위해 윈도우는 다이얼로그 박스의 구조를 표현하고 있는 파일을 읽고 다이얼로그 박스 내의 각 컨트롤을 생성하기 위해 CreateWindow를 반복적으로 호출해야 한다. 이러한 과정은 상당한 시간을 소요하게 된다. 따라서 특정 애플리케이션에 WM_KEY 메시지를 포스트하려는 경우에는 WaitForInputIdle 함수를 호출하여 다이얼로그 박스가 완전히 생성되고 사용자 입력을 기다리는 상황이 될 때까지 대기해야 한다. 이후에 키 입력 메시지를 다이얼로그 박스에 전송해야만 수행하고자 하는 작업을 정확히 수행할 수 있다.

16비트 윈도우 애플리케이션을 개발하는 개발자의 경우 종종 이러한 문제를 겪게 될 것이다. 애플리케이션 메시지를 윈도우에 포스트하는 경우 언제 메시지가 처리되어 윈도우가 생성되고 메시지를 받아들일 준비가 될런지 알아내기가 쉽지 않다. 이 경우 WaitForInputIdle 함수를 사용하면 된다.

출처 : 제프리 리처의 Windows via C/c++
2009. 8. 28. 07:14

클립보드(Clipboard)에 비트맵 저장 & 로드

클립보드에 비트맵을 저장하는 방법과 다시 그 비트맵을 클립보드로부터 로드하여 파일에 저장하는 코드 예이다.

원본 출처 : http://soulfree.net/187


CMaptoolDoc* pDoc = GetDocument();


   HANDLE                    hDIB;   

   BITMAPFILEHEADER          bifileHdr;

   BYTE*                     lptrData;

  

   CClientDC dc(this); //클립보드로 현재 이미지를 전송

  

   CDC MemDC;

   MemDC.CreateCompatibleDC(&dc);

  

   CRect rect;

   GetClientRect(rect); //뷰 영역의 크기를 얻어온다   

   rect.right = pDoc->map_arr_x*(pDoc->tile_pixel_x+pDoc->view_size);

   rect.bottom = pDoc->map_arr_y*(pDoc->tile_pixel_y+pDoc->view_size);


   CBitmap BMP;

   BMP.CreateCompatibleBitmap(&dc, rect.Width(), rect.Height());

   CBitmap* pOldBitmap = MemDC.SelectObject(&BMP);    // 메모리 DC로 BitMap 선택.

  

   MemDC.BitBlt(0, 0, rect.Width(), rect.Height(), &dc, 0, 0, SRCCOPY);

   // 현재 화면의 내용을 메모리 DC로 전송한다.


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

   // 클립보드에 캡춰한 비트맵을 설정한다.

   OpenClipboard();        // 현재 클립보드를 연다.

   EmptyClipboard();        // 현재 클립보드의 내용을 모두 제거한다.

   SetClipboardData(CF_BITMAP, BMP.GetSafeHandle()); // Capture한 비트맵 설정

   CloseClipboard();


   MemDC.SelectObject(pOldBitmap);

   BMP.Detach();        // 비트맵 객체 제거


   OpenClipboard();


   //클립보드로 카피된게 DIB 형식이 아니면 바로 리턴.

   if(!IsClipboardFormatAvailable(CF_DIB))

   {

       AfxMessageBox("Image file save Fail");

       return;

   }


   hDIB = ::GetClipboardData(CF_DIB);


   if(!hDIB)

   {

       AfxMessageBox("Image file save Fail");

       CloseClipboard();

       return;

   }   


   CloseClipboard();


   //비트맵 헤더의 크기를 계산하고

   bifileHdr.bfType        = 0x4D42;

   bifileHdr.bfSize        = sizeof(BITMAPFILEHEADER) + GlobalSize(hDIB);

   bifileHdr.bfReserved1    = 0;

   bifileHdr.bfReserved2    = 0;

   bifileHdr.bfOffBits        = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);

  


   lptrData = (BYTE *)GlobalLock(hDIB);


   char szFilter[] = "BMP File(*.bmp)|*.bmp|All Files(*.*)|*.*||";

   CFileDialog dlg(FALSE, "bmp", "*.bmp", OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, szFilter);

   if(IDOK == dlg.DoModal())

   {

       CFile file;

       file.Open(dlg.GetPathName(), CFile::modeCreate | CFile::modeWrite);    

       file.Write(&bifileHdr, sizeof(BITMAPFILEHEADER));

       file.Write(lptrData, GlobalSize(hDIB));

       file.Close();      

   }

   GlobalUnlock(hDIB);

   GlobalFree(hDIB);  

참조사이트

http://www.codeguru.com/Cpp/G-M/bitmap/capturing/article.php/c4919/

http://www.codeguru.com/Cpp/G-M/bitmap/capturing/article.php/c4915/

2009. 7. 4. 10:14

EXE 안에 외부의 데이터파일 저장하기

MSDN의 How Do I: Store External Data Files Within an EXE? 강좌를 정리한 것이다.
링크는 맨 아래 참고

이 강좌는 리소스에 XML 을 추가하고, 그 리소스를 다시 로드하는 방법에 대해서 설명하였다. 그 중에서 가장 중요한 코드 부분은 다음과 같다.

// Stuff contents of XML resource into the edit box

// FindResource, LoadResource, LockResource, SizeofResource

HRSRC hResource = FindResource(AfxGetResourceHandle(), MAKEINTRESOURCE(IDR_CUSTOMXML), _T("XML") );

HGLOBAL hMem = LoadResource(AfxGetResourceHandle(), hResource);

LPCSTR pResource = (LPCSTR) LockResource(hMem);

 

DWORD dwSize = SizeofResource(AfxGetResourceHandle(), hResource);

LPSTR pXMLBuf = new char[dwSize+1];

CopyMemory (pXMLBuf, pResource, dwSize);

pXMLBuf[dwSize] = '\0';

 

CString temp(pXMLBuf);

m_editXML.SetWindowText(temp);

 

// Cleanup

delete[] pXMLBuf;

FreeResource(hMem);




원본 : http://msdn.microsoft.com/ko-kr/visualc/bb851553(en-us).aspx


2009. 7. 3. 09:30

간단하게 취소 기능 구현하기

반복문을 수행중일 때는 취소하는 기능을 넣고 싶을때가 많다. 이럴때는 단순하게 생각하고 다음과 같이 해결해 버리자.

for(long i=0; i<10000; i++)

{

        // do something

        if( GetAsyncKeyState(VK_ESCAPE) & 0x8000)

        {

               MessageBeep(-1);

               break;

        }

}


조금만 더 생각해보면  문제를 더 쉽게 해결할 수 있는 방법이 많다.

참고: http://cboard.cprogramming.com/cplusplus-programming/112970-getasynckeystate-key-pressed.html

2009. 4. 9. 14:24

WPARAM 과 LPARAM

WPARAM 과 LPARAM 의 구분은 16 비트 윈도우에서 시작되었고, 당시 W 는 Word 를 의미하여 16비트, L 은 Long 을 의미하여 32비트를 나타내었으나,

32비트 윈도우로 넘어오면서 둘다 32비트 값을 가리키게 되었으며, 사실상 Word 와 Long의 구분은 의미 없어 졌으며 예전의 관례가 남아 있는 것이다. 굳이 16 비트 윈도우에서도 작성하는 애플리케이션이 동작해야 한다면 위 구분을 고려해야 하나,

그럴 일은 거의 없을 것이다.
2009. 3. 6. 13:38

MsgWaitForMultipleObjects and the queue state

One danger of the MsgWaitForMultipleObjects function is calling it when there are already messages waiting to be processed, because MsgWaitForMultipleObjects returns only when there is a new event in the queue.

In other words, consider the following scenario:

  • PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) returns TRUE indicating that there is a message.
  • Instead of processing the message, you ignore it and call MsgWaitForMultipleObjects.

This wait will not return immediately, even though there is a message in the queue. That's because the call to PeekMessage told you that a message was ready, and you willfully ignored it. The MsgWaitForMultipleObjects message tells you only when there are new messages; any message that you already knew about doesn't count.

A common variation on this is the following:

  • MsgWaitForMultipleObjects returns that there is a message.
  • You call PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) and process that message.
  • You call MsgWaitForMultipleObjects to wait for more messages.

If it so happens that there were two messages in your queue, the MsgWaitForMultipleObjects does not return immediately, because there are no new messages; there is an old message you willfully ignored, however.

When MsgWaitForMultipleObjects tells you that there is a message in your message queue, you have to process all of the messages until PeekMessage returns FALSE, indicating that there are no more messages.

Note, however, that this sequence is not a problem:

  • PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) returns FALSE indicating that there is no message.
  • A message is posted into your queue.
  • You call MsgWaitForMultipleObjects and include the QS_ALLPOSTMESSAGE flag.

This wait does return immediately, because the incoming posted message sets the "There is a new message in the queue that nobody knows about" flag, which QS_ALLPOSTMESSAGE matches and therefore causes MsgWaitForMultipleObjects to return immediately.

The MsgWaitForMultipleObjectsEx function lets you pass the MWMO_INPUTAVAILABLE flag to indicate that it should check for previously-ignored input.

Armed with this knowledge, explain why the observed behavior with the following code is "Sometimes my program gets stuck and reports one fewer record than it should. I have to jiggle
the mouse to get the value to update. After a while longer, it falls two behind, then three..."

 

// Assume that there is a worker thread that processes records and

// posts a WM_NEWRECORD message for each new record.

 

BOOL WaitForNRecords(HANDLE h, UINT cRecordsExpected)

{

    MSG msg;

    UINT cRecords = 0;

    while (true) {

        switch (MsgWaitForMultipleObjects(1, &h,

            FALSE, INFINITE, QS_ALLINPUT)) {

    case WAIT_OBJECT_0:

        DoSomethingWith(h); // event has been signalled

        break;

    case WAIT_OBJECT_1:

        // we have a message - peek and dispatch it

        if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {

            TranslateMessage(&msg);

            DispatchMessage(&msg);

        }

        if (SendMessage(hwndNotify, WM_GETRECORDCOUNT,

            0, 0) >= cRecordsExpected) {

                return TRUE; // we got enough records

        }

        break;

    default:

        return FALSE; // unexpected failure

        }

    }

}


comment :

아래는 Library 에서 사용한 예제 코드

 

ATLINLINE ATLAPI_(BOOL) AtlWaitWithMessageLoop(HANDLE hEvent)

{

    DWORD dwRet;

    MSG msg;

 

    while(1)

    {

        dwRet = MsgWaitForMultipleObjects(1, &hEvent, FALSE, INFINITE, QS_ALLINPUT);

 

        if (dwRet == WAIT_OBJECT_0)

            return TRUE;    // The event was signaled

 

        if (dwRet != WAIT_OBJECT_0 + 1)

            break;          // Something else happened

 

        // There is one or more window message available. Dispatch them

        while(PeekMessage(&msg,0,0,0,PM_NOREMOVE))

        {

            // check for unicode window so we call the appropriate functions

            BOOL bUnicode = ::IsWindowUnicode(msg.hwnd);

            BOOL bRet;

 

            if (bUnicode)

                bRet = ::GetMessageW(&msg, NULL, 0, 0);

            else

                bRet = ::GetMessageA(&msg, NULL, 0, 0);

 

            if (bRet > 0)

            {

                ::TranslateMessage(&msg);

 

                if (bUnicode)

                    ::DispatchMessageW(&msg);

                else

                    ::DispatchMessageA(&msg);

            }

 

            if (WaitForSingleObject(hEvent, 0) == WAIT_OBJECT_0)

                return TRUE; // Event is now signaled.

        }

    }

    return FALSE;

}


2008. 12. 10. 08:47

Obtaining Directory Change Notifications

Obtaining Directory Change Notifications

An application can monitor the contents of a directory and its subdirectories by using change notifications. Waiting for a change notification is similar to having a read operation pending against a directory and, if necessary, its subdirectories. When something changes within the directory being watched, the read operation is completed. For example, an application can use these functions to update a directory listing whenever a file name within the monitored directory changes.

An application can specify a set of conditions that trigger a change notification by using the FindFirstChangeNotification function. The conditions include changes to file names, directory names, attributes, file size, time of last write, and security. This function also returns a handle that can be waited on by using the wait functions. If the wait condition is satisfied, FindNextChangeNotification can be used to provide a notification handle to wait on subsequent changes. However, these functions do not indicate the actual change that satisfied the wait condition.

Use FindCloseChangeNotification to close the notification handle.

To retrieve information about the specific change as part of the notification, use the ReadDirectoryChangesW function. This function also enables you to provide a completion routine.

To track changes on a volume, see change journals.

The following example monitors the directory tree for directory name changes. It also monitors a directory for file name changes. The example uses the FindFirstChangeNotification function to create two notification handles and the WaitForMultipleObjects function to wait on the handles. Whenever a directory is created or deleted in the tree, the example should update the entire directory tree. Whenever a file is created or deleted in the directory, the example should refresh the directory.

Note  

This simplistic example uses the ExitProcess function for termination and cleanup, but more complex applications should always use proper resource management such as FindCloseChangeNotification where appropriate.


 #include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <tchar.h>

void RefreshDirectory(LPTSTR);
void RefreshTree(LPTSTR);
void WatchDirectory(LPTSTR);

void _tmain(int argc, TCHAR *argv[])
{
    if(argc != 2)
    {
        _tprintf(TEXT("Usage: %s <dir>\n"), argv[0]);
        return;
    }

    WatchDirectory(argv[1]);
}

void WatchDirectory(LPTSTR lpDir)
{
   DWORD dwWaitStatus;
   HANDLE dwChangeHandles[2];
   TCHAR lpDrive[4];
   TCHAR lpFile[_MAX_FNAME];
   TCHAR lpExt[_MAX_EXT];

   _tsplitpath_s(lpDir, lpDrive, 4, NULL, 0, lpFile, _MAX_FNAME, lpExt, _MAX_EXT);

   lpDrive[2] = (TCHAR)'\\';
   lpDrive[3] = (TCHAR)'\0';
 
// Watch the directory for file creation and deletion. 
   dwChangeHandles[0] = FindFirstChangeNotification(
      lpDir,                          // directory to watch
      FALSE,                          // do not watch subtree
      FILE_NOTIFY_CHANGE_FILE_NAME);  // watch file name changes
 
   if (dwChangeHandles[0] == INVALID_HANDLE_VALUE)
   {
     printf("\n ERROR: FindFirstChangeNotification function failed.\n");
     ExitProcess(GetLastError());
   }
 
// Watch the subtree for directory creation and deletion. 
   dwChangeHandles[1] = FindFirstChangeNotification(
      lpDrive,                       // directory to watch
      TRUE,                          // watch the subtree
      FILE_NOTIFY_CHANGE_DIR_NAME);  // watch dir name changes
 
   if (dwChangeHandles[1] == INVALID_HANDLE_VALUE)
   {
     printf("\n ERROR: FindFirstChangeNotification function failed.\n");
     ExitProcess(GetLastError());
   }
 

// Make a final validation check on our handles.
   if ((dwChangeHandles[0] == NULL) || (dwChangeHandles[1] == NULL))
   {
     printf("\n ERROR: Unexpected NULL from FindFirstChangeNotification.\n");
     ExitProcess(GetLastError());
   }

// Change notification is set. Now wait on both notification
// handles and refresh accordingly. 
   while (TRUE)
   {
   // Wait for notification.
      printf("\nWaiting for notification...\n");

      dwWaitStatus = WaitForMultipleObjects(2, dwChangeHandles,
         FALSE, INFINITE);
 
      switch (dwWaitStatus)
      {
         case WAIT_OBJECT_0:
 
         // A file was created, renamed, or deleted in the directory.
         // Refresh this directory and restart the notification.
             RefreshDirectory(lpDir);
             if ( FindNextChangeNotification(dwChangeHandles[0]) == FALSE )
             {
               printf("\n ERROR: FindNextChangeNotification function failed.\n");
               ExitProcess(GetLastError());
             }
             break;
 
         case WAIT_OBJECT_0 + 1:
 
         // A directory was created, renamed, or deleted.
         // Refresh the tree and restart the notification.
             RefreshTree(lpDrive);
             if (FindNextChangeNotification(dwChangeHandles[1]) == FALSE )
             {
               printf("\n ERROR: FindNextChangeNotification function failed.\n");
               ExitProcess(GetLastError());
             }
             break;
 
         case WAIT_TIMEOUT:

         // A time-out occurred. This would happen if some value other
         // than INFINITE is used in the Wait call and no changes occur.
         // In a single-threaded environment, you might not want an
         // INFINITE wait.
 
            printf("\nNo changes in the time-out period.\n");
            break;

         default:
            printf("\n ERROR: Unhandled dwWaitStatus.\n");
            ExitProcess(GetLastError());
            break;
      }
   }
}

void RefreshDirectory(LPTSTR lpDir)
{
   // This is where you might place code to refresh your
   // directory listing, but not the subtree because it
   // would not be necessary.

   _tprintf(TEXT("Directory (%s) changed.\n"), lpDir);
}

void RefreshTree(LPTSTR lpDrive)
{
   // This is where you might place code to refresh your
   // directory listing, including the subtree.

   _tprintf(TEXT("Directory tree (%s) changed.\n"), lpDrive);
}



From :

MSDN (http://msdn.microsoft.com/en-us/library/aa365261(VS.85).aspx)

Another Reference Sites :

CFileChangeEvent Class (http://www.codeproject.com/KB/files/filechange.aspx)
How to get a notification if change occurs in a specified directory (http://www.codeproject.com/KB/files/DirCheck.aspx)
2008. 12. 10. 08:35

소멸자를 이용한 뮤텍스 권한 소유 및 해제


소멸자를 이용한 테크닉은 어디에서나 활용할 수 있다. 이런 방식을 잊지 말고 활용하자.

 

class CSimpleLock

{

public:

// Lock

CSimpleLock(HANDLE hMutex)

{

m_hMutext = hMutex;

WaitForSingleObject(hMutext, INFINITE);

}

// Unlock

~CSimpleLock()

{

ReleaseMutex(m_hMutex);

}

private:

HANDLE m_hMutex;

};


출처 : Inside COM