conime -> Console IME -> Console Microsoft Global Input MEthod

NT계열 OS에서 제공하는 cmd와 같은 콘솔에서 한글을 지원할 수 있도록 제공되는 프로세스이다.
cmd와 command와 같은 콘솔을 띄우게 되면 한글 윈도우에선 자동으로 로딩된다. 물론 수동으로
프로세스 메니저에서 지우지 않는 이상 사라지는건 수동이다.

콘솔을 사용하면 자동으로 한글 지원을 위하여 생성되는 프로세스이므로 걍 나둬도 상관없다.

뜨지 않도록 설정하는 방법.
------------------------
1. regedit.exe 를 실행시킨다.
2. HKEY_CURRENT_USER\Console의 LoadConIme 값을 0으로 설정한다.
3. 저 값이 없으면 만들어 넣는다.

키워드 [Programming][VC++][Icon][Merge]
http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=51&MAEULNo=20&no=265&ref=192

이번에 쓰는 팁은 아주 간단한 겁니다... 파일이나 폴더 브라우져를 만드시는 분에게
꼭 필요한 팁이 아닐까 생각합니다.
강좌를 중단한건 엄청 잘못했지만 그래도 관련된 자료나 팁은 계속 올리겠습니다.

이번에 사용되는 팁은 아이콘을 표시할 때 공유되는 폴더나 바로가기 아이콘 처럼
원래의 아이콘에 오버레이된 이미지를 사용하여 원하는 아이콘을 만들어 사용하는
팁입니다.
디바이스 컨텍스나 이미지 처리를 하지않고 사용할 수 있는 간단한 방법이지요... ^^;;;

여기서는 바로가기 아이콘을 흉내낸 처리루틴입니다.

// hiFolder는 원본 아이콘
HICON GetLinkedIcon(HICON hiFolder)
{
    // 리턴할 아이콘
    HICON hiShared;
    // 바로가기의 쪼그만 사각형에 화살표가 들은 아이콘을 저장할 핸들
    HICON hiHand;

    // 바로가기의 쪼그만 사각형 아이콘 핸들을 얻어온다.
    ExtractIconEx("shell32.dll", 29, &hiHand, NULL, 1);

    // 주어진 플래그대로 HIMAGELIST 를 만든다.
    HIMAGELIST himl = ImageList_Create(32, 32, ILC_MASK, 1, 0);

    // 아이콘의 Merge 처리를 위하여 이미지 리스트에 추가한다.
    ImageList_AddIcon(himl, hiFolder);
    ImageList_AddIcon(himl, hiHand);

    // 두개의 아이콘을 Merge 시킨다.
    HIMAGELIST himlNew = ImageList_Merge(himl, 0, himl, 1, 0, 0);

    // 이미지 리스트에서 Merge된 아이콘을 찾아낸다.
    hiShared = ImageList_ExtractIcon(0, himlNew, 0);

    // 다쓴 아이콘 지우기
    DestroyIcon(hiHand);

    // 다쓴 이미지 리스트 지우기
    ImageList_Destroy(himl);
    ImageList_Destroy(himlNew);

    // 완성된 아이콘 돌려주기
    return hiShared;
}

키워드 [Programming][VC++][Tip]
http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=51&MAEULNo=20&no=769&ref=450

오늘 작업을 하다가 또다시 precompiled error라는 넘과 부딭히는 불쌍사가
발생하였습니다.
갑자기 먼 이유로 이런 현상이 발생하는지는 잘 몰랐구여, 발생원인은
아직도 모릅니다.

지금까지 질문과 답변을 보면 프리컴파일을 하지 않는 다는 셑팅 옵션을 첵크해서
뛰어난 기능을 막아버리고 답답하게 쓰거나, 간단한 프로젝트라면 다시 만드는
경우도 많았습니다.

그러다 결국 오늘 자밨습니다. 푸하하하하

셑팅의 결과는 그림으로 화면을 캪쳐하여 올려 놓아습니다.

완벽하게 동작하더군여.. 푸헐..

프로젝트 셑팅과 각각의 파일 셑팅의 차이점을 그림으로 올려 놓았으니..

보시면 한방에 해결하실 수 있을겁니다..

푸하하.. 오늘은 푸근한 맘으로 잠들 수 있으려나.. ^^

다시 #########################################################################

이미지로 캡쳐해서 올려 놓았는데.. 파일을 볼 수가 없다는 군여.. --;;;

그래서, 간단하게 설명도 함께 올립니다. (그림 보면 한방인데 --;;;)

먼저 [프로젝트]-[셑팅]-[C/C++]

여기에서 Category - Precompiled Headers 를 선택합니다.

1. 먼저 왼쪽에 보이는 트리에서 프로젝트를 통채로 선택합니다.

그리고, use precompiled header file[.pch] 이 넘을 선택하고
에디터에 stdafx.h 를 써넣습니다.

2. 그리고 프로젝트 아이템을 열어서 각각의 파일을 하나씩 선택하여 위와 같이
동일하게 모두 선택해 줍니다.

3. 마지막으로 stdafx.cpp 란 넘은 이넘들과 다르게 처리해야 합니다.
이넘이 프리 컴파일헤더 파일을 만드는데 결정적인 영향을 미치는 파일입니다.

이것은 create precompiled header file[.pch] 를 선택합니다.
그리고 에디터에 stdafx.h 라구 쓰시면 됩니다.

이것 때문에 고생한적이 한두번이 아닌데..아주 속이 시원하군여.

그럼 즐푸하세여 ^^

키워드 [Programming][VC++][Security]
http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=51&MAEULNo=20&no=5736&ref=5736

사용 환경..
Windows NT/2000: Requires Windows 2000 (or Windows NT 4.0 SP6a or later with DSClient).
Windows 95/98: Requires Windows 95/98 (with IE 4.01 or later and DSClient). Not supported on Windows Me.
Header: Declared in Adshlp.h, Iads.h
Library: Use ActiveDS.Lib, ADSIid.Lib, Adptif.Lib


코드

#include <Iads.h>
#include <Adshlp.h>

HRESULT CheckUserGroups(IADsUser *pUser)
{
    IADsMembers *pGroups;
    HRESULT hr = S_OK;
    hr = pUser->Groups(&pGroups);
    pUser->Release();
    if (FAILED(hr)) return hr;

    IUnknown *pUnk;
    hr = pGroups->get__NewEnum(&pUnk);
    if (FAILED(hr)) return hr;
    pGroups->Release();

    IEnumVARIANT *pEnum;
    hr = pUnk->QueryInterface(IID_IEnumVARIANT,(void**)&pEnum);
    if (FAILED(hr)) return hr;

    pUnk->Release();

    // Now Enumerate
    BSTR bstr;
    VARIANT var;
    IADs *pADs;
    ULONG lFetch;
    IDispatch *pDisp;

    VariantInit(&var);
    hr = pEnum->Next(1, &var, &lFetch);
    while(hr == S_OK)
    {
        if (lFetch == 1)
        {
             pDisp = V_DISPATCH(&var);
             pDisp->QueryInterface(IID_IADs, (void**)&pADs);
             pADs->get_Name(&bstr);
             printf("Group belonged: %S\n",bstr);
             SysFreeString(bstr);
             pADs->Release();
        }
        VariantClear(&var);
        pDisp=NULL;
        hr = pEnum->Next(1, &var, &lFetch);
    };
    hr = pEnum->Release();
    return S_OK;
}

IADsUser *GetUserObject(LPWSTR uPath)
{
    IADsUser *pUser;
    HRESULT hr = ADsGetObject(uPath,IID_IADsUser,(void**)&pUser);
    if (FAILED(hr)) {return NULL;}
    BSTR bstr;
    hr = pUser->get_FullName(&bstr);
    printf("User: %S\n", bstr);
    SysFreeString(bstr);
    return pUser;
}

void main()
{
    HRESULT hr = CoInitialize(NULL);
    IADsUser *pUser = (IADsUser*)GetUserObject(
                      L"WinNT://KWONJH/Rkakr,user");
    pUser->AddRef();
    hr = CheckUserGroups(pUser);
    if(pUser) pUser->Release();
    CoUninitialize();
}

예제 설명..
위이 상단 두 함수는 MSDN을 참조하여 구성한 것이고..
아래의 main 문에서 실제 정보를 추출하는데 필요한 GetUserObject()에 전달되는 인자 타입에 대하여 설명한다.

IADsUser *pUser = (IADsUser*)GetUserObject( L"WinNT://KWONJH/Rkakr,user");

WinNT://KWONJH/Rkakr,user

여기서 WinNT는 NT커널임을 이야기 한다.
JWONJH는 컴터의 이름이다... 혹은 다른 컴터의 이름이나 도메인 이름이 될 수 있다.
Rkakr 는 사용자의 유저 이름이다.

혹시나 이것을 지금 로그온 한 사람의 유저 이름으로 할려면 간단하게..
char *logname =getenv("USERNAME");
이렇게 읽어 오면 된다.
user 요건은 사용자를 말하며.. 컴터를 찾을 경우는 computer라고 입력하면 된다.

실제로 위의 정보가 맞다면..

CheckUserGroups 함수 중간에 있는 프린트 문에서..
현 정보가 주어진 사용자가 속한 그룹의 리스트가 쭈~~욱 프린트 될것이다.

테스트 환경
Windows XP SP1/ Windows 2000 SP2,  VC++6.0 SP5

위의 코드를 돌려 보니 아래와 같은 결과가 나왔습니다.

User: Rkakr
Group belonged: Administrators
Group belonged: Remote Desktop Users
Group belonged: Users


그럼 즐거운 주말 되세욤 ^^;

키워드 [Programming][VC++][Base64]
걍 라이브러리로 만들어 놓은 것 중에서.. 일부를 뽑아 소스를 올린다.



/////////////////////////////////////////////////////////////
// base64 인코딩/디코딩 및 제거
// base64.h
K4LIB_BASIC_API unsigned char* base64_encode(const unsigned char *string, int length, int *ret_length);
K4LIB_BASIC_API unsigned char* base64_decode(const unsigned char *string, int length, int *ret_length);
K4LIB_BASIC_API void base64_free(unsigned char* data);




/////////////////////////////////////////////////////////////
// base64 인코딩/디코딩 및 제거
// base64.cpp
static char base64_table[] =
{ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', '\0'
};
static char base64_pad = '=';

unsigned char *base64_encode(const unsigned char *string, int length, int *ret_length)
{
    const unsigned char *current = string;
    int i    = 0;
    int    wi    =    0;
    int        nAllocSize    =    ((length + 3 - length
  % 3) * 4 / 3 + 1) * sizeof(char);
    nAllocSize    +=    (nAllocSize/80+1)*2;
    unsigned char *result = new unsigned char[nAllocSize];
 
    while (length > 2)
    { /* keep going until we have less than 24 bits */
        result[i++] = base64_table[current[0] >> 2];
        result[i++] = base64_table[((current[0] & 0x03) <<  4)
   + (current[1] >> 4)];
        result[i++] = base64_table[((current[1] & 0x0f) <<  2)
   + (current[2] >> 6)];
        result[i++] = base64_table[current[2] & 0x3f];
 
        current += 3;
        length -= 3; /* we just handle 3 octets of data */
        wi+=4;
 
/*        if(wi%80 == 0)
        {
            result[i++] = '\r';
            result[i++] = '\n';
        }
*/    }
 
    /* now deal with the tail end of things */
    if (length != 0)
    {
        result[i++] = base64_table[current[0] >> 2];
        if (length > 1)
        {
            result[i++] = base64_table[((current[0] &
    0x03) <<  4) + (current[1] >> 4)];
            result[i++] = base64_table[(current[1] &
    0x0f) <<  2];
            result[i++] = base64_pad;
        }else
        {
            result[i++] = base64_table[(current[0] &
    0x03) <<  4];
            result[i++] = base64_pad;
            result[i++] = base64_pad;
        }
    }
    if(ret_length)
    {
        *ret_length = i;
    }
    result[i] = '\0';
    return result;
}

/* as above, but backwards. :) */
unsigned char *base64_decode(const unsigned char *string, int length, int *ret_length)
{
    const unsigned char *current = string;
    int ch, i = 0, j = 0, k;
    char *chp;
 
    unsigned char *result = new unsigned char[(length / 4 *3 + 1) * sizeof(char)];
    if (result == NULL) {
        return NULL;
    }
 
    /* run through the whole string, converting as we go */
    while ((ch = *current++) != '\0') {
        if (ch == base64_pad) break;
        chp = strchr(base64_table, ch);
        if (chp == NULL) continue;
        ch = chp - base64_table;
 
        switch(i % 4) {
        case 0:
            result[j] = (unsigned char)(ch <<  2);
            break;
        case 1:
            result[j++] |= ch >> 4;
            result[j] = (unsigned char)((ch & 0x0f) <<  4);
            break;
        case 2:
            result[j++] |= ch >>2;
            result[j] = (unsigned char)((ch & 0x03) <<  6);
            break;
        case 3:
            result[j++] |= ch;
            break;
        }
        i++;
    }
 
    k = j;
    /* mop things up if we ended on a boundary */
    if (ch == base64_pad) {
        switch(i % 4) {
        case 0:
        case 1:
            delete [] result;
            return NULL;
        case 2:
            k++;
        case 3:
            result[k++] = 0;
        }
    }
    if(ret_length) {
        *ret_length = j;
    }
    result[k] = '\0';
    return result;
}

void base64_free(unsigned char* data)
{
 delete[] data;
}


키워드 [Programming][VC++][MD5]
http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=51&MAEULNo=20&no=6446&ref=6446

많이 사용되는 MD5 기법을 MFC에서 사용하기 간단한 클래스로 구현한 자료를 올립니다..
편하게 사용하세요.. 라이센스?? 던주면 감사히 받구요..
 
MD5가 머냐고 의문이 생기시는 분은 관련분야에 종사하시면 레퍼런스를 참고하시구요, 관련 분야가 아니시면, 걍 암호화의 한 부분이라고 생각하시면 됩니다.... 복잡하게 생각하면 머리 터져요 ^^;
 
간단히 헤더만 정리해 보면...
 
// MD5.h: interface for the CMD5 class.
//
//////////////////////////////////////////////////////////////////////
 
#if !defined(AFX_MD5_H__1E84B7F9_E0C0_4075_9CB1_3366A8363F48__INCLUDED_)
#define AFX_MD5_H__1E84B7F9_E0C0_4075_9CB1_3366A8363F48__INCLUDED_
 
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
 
class CMD5 
{
    typedef struct
    {
        UINT state[4];                                   /* state (ABCD) */
        UINT count[2];        /* number of bits, modulo 2^64 (lsb first) */
        BYTE buffer[64];                         /* input buffer */
    } MD5_CTX;
 
public:
    CMD5();
    virtual ~CMD5();
    CString GetString(CString str);
 
protected:
    void MD5Init(MD5_CTX* ctx);
    void MD5Update(MD5_CTX* ctx, BYTE* input, UINT inputlen);
    void MD5Final(BYTE* digest, MD5_CTX* ctx);
};
 
#endif // !defined(AFX_MD5_H__1E84B7F9_E0C0_4075_9CB1_3366A8363F48__INCLUDED_)

코드를 보시면 알겠지만.. 걍 선언해놓구.. GetString() 함수만 호출하는 간한단 구조로 되어 있습니다..
샘플 코드

CMD5 md5;
TRACE("%s\n", md5.GetString("dfsafafadffsdfsfsf"));

Output : 9632F1DC3D8E35BFF71D1D86E3E1EB9D

그럼 즐프 하세요..

키워드 [Programming][VC++][Tip]
http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=51&MAEULNo=20&no=6499&ref=6499

질문글에 답변을 달다가.. 언뜻 스쳐지나간 MSDN 내용을 찾아서.. 올려봅니다.

현재 내가 실행시킨 프로그램이 스스로 떠 있는 상태에서 자기 자신의 실행파일을 다른 곳으로 이동하는 질문이
있어서.. 기억을 살려 보았습니다.

일반적으로 구동중인 실행파일이나.. 그런것을 지울 수는 없습니다.
공유 에러를 발생시키기 때문이죠.

근디, 윈도의 치명적인 버그인지는 몰라도 이동은 가능합니다.
(버그일까.. 아님 일부러 그렇게 가능하도록 만든 것일까.. ???? )

물론 다른 파티션이나 드라이브로의 이동은 불가능합니다.
하지만 동일한 드라이브 내에서의 이동은 가능하죠.

정확하게 확인한것은 아니지만, 메모리와 메핑되어 있는 파일의 영역은 그대로 살리고
NTFS의 링크만 이동하는것으로 짐작합니다.

즉, 탐색기 상에서는 파일이 이동한 것으로 보이지만, 링크만 바뀌었을 뿐 메핑된 파일 영역은 디스크상에
그 위치 그대로 존재하게 되는 것이겠죠.

위와 같은 동작을 하기위해서는 Window 2000 이상에서만 가능합니다...
파티션이 NTFS이어야만 하는 지는 잘 모르겠고, FAT16 or FAT32 는 실험해보지 않았습니다.

#define WINVER 0x0500
#define _WIN32_WINNT 0x0500

MoveFileEx(original path, move path, MOVEFILE_FAIL_IF_NOT_TRACKABLE);

PS. 참고로 이동할 경로에 동일한 이름을 가진 파일이 존재하면 에러 납니다..

----------------------------------------------------------------------------------------

정일호 (madness_kr)   정일호님께 메시지 보내기정일호님을 내 주소록에 추가합니다.정일호님의 개인게시판 가기 
Window 2000. FAT32 에서도 잘 되네요...

키워드 [Programming][VC++][API]
http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=51&MAEULNo=20&no=6761&ref=6761


디렉토리에 대한 변경이 발생하면, 발생한 이벤트와 경로를 큐에 저장
2. 큐 처리 전용스레드를 이용하여, 만약 부모 윈도 핸들을 주면, PostMessage로 정보 전송

조언을 듣고 코드 프로젝트에도 잘 꾸며진 소스를 살펴밨습니다만...
제가 사용하기에는 코드가 좀 크고 복잡해서 잘 분석이 않되네요.
그래서, 이전 버전을 좀더 업데이트 해봤습니다.
앞으로 필요에 의해 쭈욱 업데이트를 하겠지만, 제 본래 작업과는 거리가 먼 분야라..

짬짬이..  ^^;
참고로, 실행파일과 샘플 프로젝트를 올립니다.
샘플은 C:\와 D:\에 걸쳐 동작하도록 두개를 돌렸습니다.
대략.. 3개 드라이브에..  CD 한장 분량을 복사하고 해봐도.. 큰 문제는 없군요.
버그도 좀 있으면, 리플주세요

구조가 좀 지저분한데, 혹시나 정리하시는 분이 생기시면 업데이트 해주세요 ^^;

키워드 [Programming][VC++][Regsitry]
http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=51&MAEULNo=20&no=7471&ref=7471

// 레지스트리를 설정한 후 키이름을 변경할 만한 방법이 없어서 구현해봤습니다.
// 직접적으로 이름의 변경이 가능한건 아니고, 현재 열린 키를 포함 하위를 몽땅
// 파일로 백업한 다음에, 변경할 새 키로 몽땅 리스토어 한후, 기존 키를 지웁니다.

// 대상 키는 미리 만들어 주셔야 하며, 그게 귀찬을 경우
// 소스를 조금 수정하시면 없을 경우는 만들고 동작하도록 구성하시면 됩니다.

BOOL SetPrivilege(LPCTSTR lpszPrivilege, BOOL bEnablePrivilege = TRUE)
{
    HANDLE hToken;
 
    if(!::OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
  return FALSE;
 
    TOKEN_PRIVILEGES tp;
    LUID luid;
 
    if (!LookupPrivilegeValue(NULL, lpszPrivilege, &luid )) {
        TRACE("LookupPrivilegeValue error: %u\n", GetLastError() );
        return FALSE;
    }
 
    tp.PrivilegeCount = 1;
    tp.Privileges[0].Luid = luid;
    if (bEnablePrivilege)
  tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
 else
  tp.Privileges[0].Attributes = 0;
 
 if ( !AdjustTokenPrivileges(hToken, FALSE,  &tp, sizeof(TOKEN_PRIVILEGES), (PTOKEN_PRIVILEGES) NULL, (PDWORD) NULL) ) {
  TRACE("AdjustTokenPrivileges error: %u\n", GetLastError() );
  return FALSE;
 }
 
 if (GetLastError() == ERROR_NOT_ALL_ASSIGNED) {
  TRACE("The token does not have the specified privilege. \n");
  return FALSE;
 }
 
 return TRUE;
}

#define TEMP_BACK_FILE  "_#temp"

BOOL RegRenameKey(HKEY srcROOT, const char* srcSUB, HKEY dstROOT, const char* dstSUB)
{
 HKEY hKeySrc=0, hKeyDst=0;
 DWORD Ret;
 
 // 저장할 때는 SeBackupPrivilege, 복구할 때는 SeRestorePrivilege 권한이 필요하다. msdn 발췌
 if( !SetPrivilege("SeBackupPrivilege") || !SetPrivilege("SeRestorePrivilege") )
  return FALSE;
 
 if( RegOpenKeyEx(srcROOT, srcSUB, 0, KEY_ALL_ACCESS, &hKeySrc) != ERROR_SUCCESS ||
  RegOpenKeyEx(dstROOT, dstSUB, 0, KEY_ALL_ACCESS, &hKeyDst) != ERROR_SUCCESS )
  return FALSE;
 
 Ret = RegSaveKey(hKeySrc, TEMP_BACK_FILE, NULL);
 if(ERROR_SUCCESS != Ret)
 {
  RegCloseKey(hKeySrc);
  DeleteFile(TEMP_BACK_FILE);
  return FALSE;
 }
 RegCloseKey(hKeySrc);
 hKeySrc = 0;
 
 Ret = RegRestoreKey(hKeyDst, TEMP_BACK_FILE, REG_FORCE_RESTORE | REG_NO_LAZY_FLUSH);
 if(ERROR_SUCCESS != Ret)
 {
  RegCloseKey(hKeyDst);
  DeleteFile(TEMP_BACK_FILE);
  return FALSE;
    }
 
    RegCloseKey(hKeyDst);
    SHDeleteKey(srcROOT, srcSUB);
    return TRUE;
}

----------------------------------------------------------------------------------------------

오승우 (Ċhobits)   오승우님께 메시지 보내기오승우님을 내 주소록에 추가합니다.오승우님의 개인게시판 가기  61.75.68.12
참고로 XP이상에선 NtDll.dll에 native API NtRenameKey가 있습니다.
http://www.codeproject.com/system/NtRegistry.asp

키워드 [Programming][VC++][Multimedia]
http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=51&MAEULNo=20&no=7518&ref=7518

전에도 한번 올라왔던 내용인데..
요즘 중복되는 질문 내용이 자주 보여 간단하게 정리해서 올립니다.

PlaySound()는 아주 간단하게 리소스나 파일의 wav폼 파일을 읽어서 재생할 수 있는 함수입니다.
단점이 싱크모드와 어싱크 모드로 재생이 가능한데.. 싱크모드로 돌리면 제어가 불가능하고..
어싱크모드로 돌리면 종료시 점을 알수 없다는데 있습니다.

아래의 기법을 이용하면 어싱크모드로 재생하면서 종료 시점을 알수 있고요..
Sleep에 의한 오차 100ms가 있긴 하지만.. 어쨋든...

원하는 소리를 원하는 시점에서 재생 및 중지를 시킬 수 있다는게 장점입니다.

// 소리를 재생하는 스레드입니다.
DWORD CALLBACK AAA(void* param)
{
   // 임시로 aaa.wav란 넘을 어싱크모드로 플레이 합니다.
    PlaySound("aaa.wav", NULL, SND_FILENAME | SND_ASYNC);

    while(1)
    {
        Sleep(100);

        // 재생이 끝날 때 까지 대기 합니다.
        // SND_NOSTOP 옵션이 있어서 현재 재생중일 때는 아래의 함수가 FALSE를 리턴함다.
        if(PlaySound(NULL, NULL, SND_PURGE | SND_NOSTOP | SND_NOWAIT | SND_SYNC))
            break;
    }

    return 0;
}

// 아무 곳에서나 현재 재생중인 음악을 중지 하시고 싶으시면.
// 음악을 중지시키면 당연히 위의 스레드도 바로 종료하게 됩니다.
PlaySound(NULL, NULL, SND_PURGE | SND_NOWAIT | SND_ASYNC);

+ Recent posts