Search

'Program Visual C++'에 해당되는 글 36건

  1. 2011.08.10 YUV to RGB ...
  2. 2010.10.10 쓰레드 사용 예제?? AfxBeginThread, CreateThread, _beginthreadex
  3. 2009.05.05 AfxBeginThread 사용법?
  4. 2009.02.25 Microsoft Platform SDK

YUV to RGB ...

Program Visual C++ 2011. 8. 10. 16:34 Posted by HisPark
// YUV_B, YUV_R, YUV_G 배열은 사용하기 전에 YUV_lookup_table() 함수로 초기화해야 한다.

double YY[256], BU[256], GV[256], GU[256], RV[256];
unsigned char YUV_B[256][256];
unsigned char YUV_R[256][256];
unsigned char YUV_G[256][256][256];

void YUV_lookup_table()
{
int i, j, k;
double i_value;
for( i=255; i>=0; i-- )
{
YY[i] = (1.164*(i-16.0));
BU[i] = (2.018*(i-128.0));
GV[i] = (0.831*(i-128.0));
GU[i] = (0.391*(i-128.0));
RV[i] = (1.596*(i-128.0));
}

for( i=255; i>=0; i-- ){
for( j=255; j>=0; j-- )
{
i_value = YY[i] + BU[j];
if ( i_value > 255 ) i_value=255;
else if ( i_value < 0 ) i_value=0;
YUV_B[i][j]=(int)i_value;

i_value = YY[i] + RV[j];
if ( i_value > 255 ) i_value=255;
else if ( i_value < 0 ) i_value=0;
YUV_R[i][j]=(int)i_value;
for( k=0; k<256; k++ )
{
i_value = YY[i] - (GU[j] + GV[k]);
if ( i_value > 255 ) i_value=255;
else if ( i_value < 0 ) i_value=0;
YUV_G[i][j][k] =(int)i_value;
}
}
}
}

// YUV 영상을 RGB 영상으로 바꾸는 함수
void yuv420_to_rgb( unsigned char *in, unsigned char *out, int w, int h )
{
int x,y;
double imgsize = w*h;
int w3 = w*3;
double uvsize = imgsize/4.0;

unsigned char *pY = in;
unsigned char *pV = in + (int)imgsize;
unsigned char *pU = in + (int)imgsize + (int)uvsize;

int y00, y01, y10, y11;
int u,v;
unsigned char *p;

// 윈도우에서는 영상의 상하가 거꾸로 저장되지 때문에 아래와 같이 코드 작성.
for( y=0; y<=h-2; y+=2 )
{
for( x=0; x<=w-2; x+=2 )
{
p = out + w3*(h-y-1) + x*3;
u = *pU;
v = *pV;

y00 = *pY;
y01 = *(pY+1);
y10 = *(pY+w);
y11 = *(pY+w+1);

*(p) = YUV_B[y00][u];
*(p+1) = YUV_G[y00][u][v];
*(p+2) = YUV_R[y00][v];

*(p+3) = YUV_B[y01][u];
*(p+3+1) = YUV_G[y01][u][v];
*(p+3+2) = YUV_R[y01][v];

*(p-w3) = YUV_B[y10][u];
*(p-w3+1) = YUV_G[y10][u][v];
*(p-w3+2) = YUV_R[y10][v];

*(p-w3+3) = YUV_B[y11][u];
*(p-w3+3+1) = YUV_G[y11][u][v];
*(p-w3+3+2) = YUV_R[y11][v];
pU++;
pV++;
pY = pY + 2;
}
pY = pY + w;
}

// 일반적인 경우 아래의 코드 사용함.
/*for( y=0; y<=h-2; y+=2 )
{
for( x=0; x<=w-2; x+=2 )
{
p = out + w3*y + x*3;
u = *pU;
v = *pV;

y00 = *pY;
y01 = *(pY+1);
y10 = *(pY+w);
y11 = *(pY+w+1);

*(p) = YUV_B[y00][u];
*(p+1) = YUV_G[y00][u][v];
*(p+2) = YUV_R[y00][v];

*(p+3) = YUV_B[y01][u];
*(p+3+1) = YUV_G[y01][u][v];
*(p+3+2) = YUV_R[y01][v];

*(p+w3) = YUV_B[y10][u];
*(p+w3+1) = YUV_G[y10][u][v];
*(p+w3+2) = YUV_R[y10][v];

*(p+w3+3) = YUV_B[y11][u];
*(p+w3+3+1) = YUV_G[y11][u][v];
*(p+w3+3+2) = YUV_R[y11][v];
pU++;
pV++;
pY = pY + 2;
}
pY = pY + w;
}*/
}


//////////////////////////////////////////////////////////////////////////////////////
// BMP 파일로 저장하기

int rgbSize = _imageSize.cx*_imageSize.cy*3;
BYTE* pRgb = new BYTE[rgbSize];
memset(pRgb, 0, rgbSize);

yuv420_to_rgb(_pImage, pRgb, _imageSize.cx, _imageSize.cy);

/*TCHAR curDirPath[512];
::GetModuleFileName(NULL, curDirPath, 512);
TCHAR* pExt = _tcsrchr(curDirPath, _T('\\'));
if(pExt) *pExt = 0;*/

TCHAR defExt[] = _T("bmp");
TCHAR filters[] = _T("bmp Files(*.bmp)|*.bmp|All Files(*.*)|*.*||");
DWORD flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
TCHAR cd[_MAX_PATH];
GetCurrentDirectory(_MAX_PATH, cd);

CFileDialog dlg(FALSE, defExt, 0, flags, filters, this);
dlg.m_ofn.lpstrInitialDir = cd;
if(IDOK == dlg.DoModal()){
HANDLE hFile;
hFile = CreateFile(dlg.GetPathName(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE){
CString s; s.Format(_T("Could not create file : %s (error %d)\n"), dlg.GetPathName(), GetLastError());
AfxMessageBox(s, MB_ICONSTOP|MB_OK);
return;
}

int headerSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD);
BITMAPFILEHEADER fileHeader = { ((WORD)('M'<<8)|'B'), headerSize + rgbSize, 0, 0, headerSize};
BITMAPINFOHEADER infoHeader = { sizeof(BITMAPINFOHEADER), _imageSize.cx, _imageSize.cy, 1, 24, BI_RGB, rgbSize, 0, 0, 0, 0 };
RGBQUAD rgbQuad = { 0, };

DWORD writtenLen = 0;
if(FALSE == WriteFile(hFile, &fileHeader, sizeof(fileHeader), &writtenLen, 0)){
CString s; s.Format(_T("Could not write file : %s (error %d)\n"), _T("File Header"), GetLastError());
AfxMessageBox(s, MB_ICONSTOP|MB_OK);
}

if(FALSE == WriteFile(hFile, &infoHeader, sizeof(infoHeader), &writtenLen, 0)){
CString s; s.Format(_T("Could not write file : %s (error %d)\n"), _T("Info Header"), GetLastError());
AfxMessageBox(s, MB_ICONSTOP|MB_OK);
}

if(FALSE == WriteFile(hFile, &rgbQuad, sizeof(rgbQuad), &writtenLen, 0)){
CString s; s.Format(_T("Could not write file : %s (error %d)\n"), _T("RGB Quad"), GetLastError());
AfxMessageBox(s, MB_ICONSTOP|MB_OK);
}
if(FALSE == WriteFile(hFile, pRgb, rgbSize, &writtenLen, 0)){
CString s; s.Format(_T("Could not write file : %s (error %d)\n"), dlg.GetPathName(), GetLastError());
AfxMessageBox(s, MB_ICONSTOP|MB_OK);
}
CloseHandle(hFile);
}
if(pRgb) delete [] pRgb;
#include "stdafx.h"
#include "ExThread.h"
#include "MyThread.h"
#include <process.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

CWinApp theApp;
using namespace std;

UINT WorkerThreadFunction(void *pData)
{
    printf("Worker Thread Function\n");
    return 0;
}

DWORD WINAPI ThreadFunction(void *pData)
{
    printf("Thread Function\n");
    return 0;
}

unsigned int WINAPI ThreadFunction2(void *pData)
{
    printf("Thread Function2\n");
    return 0;
}

/*
    사용자 인터페이스 쓰레드 (User Interface Thread) 생성
    설명의 편의상, 본 예제에서 사용되고 있는 CMyThread는 CWinThread를 상속받은 클래스라고 가정합니다.
*/
void Example1()
{
    CMyThread *p = NULL;

    /* 정지된 상태로 쓰레드를 생성함. */
    p = (CMyThread *) AfxBeginThread(RUNTIME_CLASS(CMyThread), 0, 0, CREATE_SUSPENDED);

    /* 쓰레드를 다시 시작함. */
    p->m_bAutoDelete=TRUE;
    p->ResumeThread();
    Sleep(3000);

    /* 다음과 같이 사용자 인터페이스 쓰레드는 메시지를 주고 받을 수 있습니다.   */
    p->PostThreadMessage(WM_QUIT, 0, 0);    /* UI 쓰레드 종료 메시지 전송 */
    WaitForSingleObject(p->m_hThread, INFINITE);
}

/*
    작업자 쓰레드 (Worker Thread) 생성
*/
void Example2()
{
    CWinThread *p = AfxBeginThread(WorkerThreadFunction, NULL);
    WaitForSingleObject(p->m_hThread, INFINITE);
}

void Example3()
{
    HANDLE h = CreateThread(NULL, 0, ThreadFunction, NULL, 0, NULL);
    WaitForSingleObject(h, INFINITE);
    CloseHandle(h);
}

void Example4()
{
    HANDLE h = (HANDLE)_beginthreadex(NULL, 0, ThreadFunction2, 0, 0, NULL);
    WaitForSingleObject(h, INFINITE);
    CloseHandle(h);
}

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
    Example1();
    Example2();
    Example3();
    Example4();

    printf("done\n");

    return 0;
}

'Program Visual C++' 카테고리의 다른 글

RAW Data Draw  (0) 2011.08.11
YUV to RGB ...  (0) 2011.08.10
AfxBeginThread 사용법?  (0) 2009.05.05
Microsoft Platform SDK  (0) 2009.02.25
RichEdit 관련  (0) 2008.02.29

AfxBeginThread 사용법?

Program Visual C++ 2009. 5. 5. 17:04 Posted by HisPark
Threads and Thread synchronization
Threads
MFC는 2종류의 쓰레드로 구분할 수 있다.


1. user interface threads
메시지 루프가 존재한다. 윈도우를 만들고 이들 윈도우로 보내진 메시지들을 처리한다. 어플리케이션안에 또하나의 어플리케이션(ui-threads)을 만드는것과 비슷하다.일반적으로 별개로 움직이는 다중 윈도우를 만들때 많이 사용되어 진다.


2. worker threads
직접적으로 메시지를 받지 않고 백그라운드에서 동작되기 때문에 윈도우나 메시지루프들이 필요가 없다.

%이 둘간의실질적인 차이는 아직 잘모르겠다. 좀 더 학습하도록



-Creating a Worker Thread
AfxBeginThread함수는 ui-thread,worker thread 둘다 쓰인다. MFC프로그램에서 Win32::CreateThread함수를 사용하지 말아라.

ex)
CWinThread* pThread = AfxBeginThread (ThreadFunc, &threadInfo);

UINT ThreadFunc (LPVOID pParam)
{
    UINT nIterations = (UINT) pParam;
    for (UINT i=0; i<nIterations; i++);
    return 0;
}


CWinThread* AfxBeginThread (AFX_THREADPROC pfnThreadProc,
    LPVOID pParam, int nPriority = THREAD_PRIORITY_NORMAL,
    UINT nStackSize = 0, DWORD dwCreateFlags = 0,
    LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL)

nPriority : 쓰레드 우선순위. 쓰레드들 중에서만 상대적인 우선순위를 정할때 사용한다.
nStackSize : 쓰레드의 스택사이즈 라는데 정확히 뭔지..몰라.
dwCreateFlags : 0 일 경우, 이 함수 호출후 바로 쓰레드가 시작되는 것이고,
  CREATE_SUSPENDED일 경우, ResumeThread()가 호출되어야지만 시작되는것이다.
lpSecurityAttrs : 몰라도 되.


--Thread Function prototype
콜백함수이기에 static class 멤버 함수이거나 클래스 밖에 선언된 전역함수이어야 한다.
UINT ThreadFunc( LPVOIDpParam )
pParam : 32비트값. AfxBeginThread 함수의 파라미터. 이것은 scalar,handle,객체포인터로도 사용되어 질수 있다.



-Creating a UI Thread
CWinThread를 상속받은 클래스를 사용한다.

ex)
class CMyThread : public CWinThread

CMyThread * pThread = AfxBeginThread(RUNTIME_CLASS(CMyThread),
                                    THREAD_PRIORITY_NORMAL,
                                    0, // stack size
                                    CREATE_SUSPENDED);
pThread->초기값 설정.
pThread->ResumeThread();


또는

CMyThread * pThread = new CMyThread();
pThread->초기값 설정.
pThread->CreateThread();


-Suspending and Resuming Threads
SuspendThread를 호출하면 쓰레드는 멈추고, 내부적으로 Suspend count 가 1 증가 한다. 그리고 ResumeThread를 호출하면 Suspend count는 1 줄고 쓰레드는 다시 움직인다.
ResumeThread는 자신이 호출 할 수 없다. 그리고 이들 함수의 리턴값은 쓰레드의 이전 Suspend Count이다.



-Putting Threads to sleep
::Sleep(0)
현재쓰레드를 중지하고 스케쥴러가 동등한 혹은 높은 우선순위를 갖는 다른 쓰레드를 움직이도록 허락해준다. 만약, 다른 동등한 혹은 높은 우선순위의 쓰레드가 wait 상태가 아니라면, 이 함수는 바로 리턴해서 현재쓰레드를 재시작 한다. (::SwitchToThread.(in NT 4.0 ), ::Sleep(0) (in win32 ))
Sleep함수의 시간은 정확하지 않을 수 있다. 이는 여러환경에 지배받기때문이다. 윈도우즈에서는 쓰레드의 suspend 시간을 보장하는 함수는 존재하지 않는다.





-Terminating a Thread


--Worker Thread
call AfxEndThread.
쓰레드 함수내부의 리턴으로 종료.




--UI Thread
call AfxEndThread.
post WM_QUIT.( ::PostQuitMessage )

(쓰레드 종료함수 사용시 주의할것은 쓰레드 내부에 메모리를 동적할당(new,malloc)해놓고 delete를 안해서 메모리 릭이 날 염려가 있다. 그래서 가급적이면 쓰레드 함수 리턴으로 종료하는 것이 낫다.)

위의 함수들을 호출한 후 한번 제대로 종료됬는지 확인해보라
DWORD dwExitCode;
::GetExitCodeThread (pThread->m_hThread, &dwExitCode);

만약 여전히 살아 있다면 dwExitCode = STILL_ACTIVE(0x103) 으로 되어 있을테다.





- CWinThread 개체 자동 삭제하기

AfxBeginThread 로 스레드 생성할 경우,




CWinThread *pThread = AfxBeginThread( , ,, );




위와 같이 CWinThread 개체 포인터를 반환값으로 받는다. 스레드 종료시, 이 개체는 어떻게 되는가?

MFC는 사용자가 따로 delete pThread; 할 필요없게 자동으로 삭제해 준다.

그런데, 여기서 문제가 있다.

스레드가 종료되지 않았다면, 아래구문은 잘못된 곳이 없다.




::GetExitCodeThread( pThread->m_hThread, &dwExitCode );

( 스레드의 현재 상태값을 반환하는 함수 )




하지만, 종료되어 pThread 개체 포인터 역시 자동으로 삭제되었다면, 위의 구문은 에러를 발생할 것인다.

pThread 는 아무것도 가리 키지 않기 때문에..




해결책)

1. m_bAutoDelete = FALSE; 설정.

-- 이는 곧 사용자가 CWinThread 개체를 delete 해주어야 함을 의미한다.

-- 스레드가 중지가 된 상태에서 m_bAutoDelete = FALSE; 를 설정해주어야 한다.




2. Win32::DuplicateHandle 함수를 호출하여 스레드 핸들의 사본을 생성하여 사용.

--해당핸들의 참조카운트가 1 -> 2로 증가되어 CloseHandle() 호출시에 다시 2 -> 1 로 감소될뿐 개체는 죽지 않고 남아있다. 물론, 사용자가 명시적으로 CloseHandle() 을 호출해야 한다.




- 다른 스레드 종료하기

1.

//Thread A

nContinue = 1;

CWinThread *pThread = AfxBeginThread( ThreadFunc, &nContinue );

...

...

nContinue = 0 ; // 스레드 B 를 종료해라.





//Thread B

UINT ThreadFunc( LPVOID pParam )

{

  int* pContinue = (int*) pParam;

  while( *pContinue )

  {

    ....

  }

  return 0;

}





2. 스레드 A는 스레드 B가 죽을때 까지 무한 기다리도록 하고 싶을 경우,




//Thread A

nContinue = 1;

CWinThread *pThread = AfxBeginThread( ThreadFunc, &nContinue );

HANDLE hThread = pThread->m_hThread; //사본 생성. 스레드B종료시 pThread 없을 경우 대비.

...

...

nContinue = 0 ; // 스레드 B 를 종료해라.

::WaitForSingleObject( hThread, INFINITE );





//Thread B

//1.의 에제와 같음





::WaitForSingleObject 은 hThread 스레드가 종료될때 까지 무한정(INFINITE) 기다리는 함수이다.  반환 값은 아래와 같다.

-- WAIT_OBJECT_0 : 그 개체가 신호를 받았다. 즉, 스레드가 종료되었다.

-- WAIT_TIMEOUT : 스레드는 살아있지만, 시간 만료로 기다리지 않고 반환되었다.




두번째 매개 변수를 0 으로 설정하고 아래와 같이 사용하는 것이 좋다.




if( ::WaitForSingleObject( hThread, 0 ) == WAIT_OBJECT_0 )

//스레드가 더이상 존재치 않는다.

else

//스레드가 여전히 실행중이다.





- ::TerminateThread( hThread, 0 );

다른 스레드를 직접삭제하는 방법은 위의 함수 딱 한가지 존재한다. 어쩔 수 없는 경우에만 사용하도록 .





MFC에서 스레드를 사용하기 전에 알아두어야 할 함수는 AfxBeginThread, AfxEndThread 이렇게 두 함수가 있다. 이 함수에 대한 인자값은 MSDN을 참고하기 바라며, 간단한 사용법을 알아보자.

AfxBeginThread(CalcIt, (LPVOID)val);

첫 번째 인자는 전역함수인데, 클래스에 포함시킬 경우 정적함수로 선언해야되고, 아니면 전역함수로 선언해서 써야한다. CalcIt 함수의 리턴값과 파라미터는 아래와 같다.

UINT CalcIt(LPVOID arg);

꼭 위의 규칙을 따라줘야 한다.

일반적으로는 위와 같이 스레드를 시작하면 된다. 그러면 스레드가 시작되고, CalcIt함수(코어 함수??)의 역할이 끝나면 자동으로 스레드를 종료한다.

하지만 스레드는 위와 같이 쓸 경우 바로 리턴해버린다. 리턴값이 0이면 정상적인 종료를 뜻하게 되는데, 사용자에게 의미있는 리턴값을 받기 위해서, 이렇게 하면 안될것이다.

그래서 사용자가 원하는 값을 리턴 받으려면 아래와 같은 방법을 쓴다.

CWinThread* pThread = AfxBeginThread(CalcIt, (LPVOID)val, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
우선 스레드를 시작하지만 정지상태로 놓는다는 뜻이다.(CREATE_SUSPENDED)

그 다음
pThread->m_bAutoDelete = FALSE;
위에서 말했듯이, 스레드가 시작되고 자기 할일이 끝나면 바로 스레드는 종료된다. 하지만 이 값을  FALSE로 해주면 종료되지 않는다. 대신 사용자가 직접 원하는 시점에 종료를 해줘야 한다.(AfxEndThread)

pThread->ResumeThread();
이제 스레드를 시작한다.

그럼 리턴값을 받아야한다.

::GetExitCodeThread(pThread->m_hThread, &returnvalue); //Get ExitCode from thread.

이 함수는 스레드로 부터 리턴값을 읽어온다. 여기에 포함되는 리턴값을 받기 위해선 위의 CalcIt 함수에 AfxEndThread를 써줘야 한다. AfxEndThread함수의 첫 번째 인자는 위 함수의 returnvalue에 들어갈 리턴값이다. 두번째 인자는 스레듣 객체를 메모리에서 제거할 것인지를 나타낸다. 기본값은 TRUE이고 메모리에서 삭제된다. FALSE이면 메모리에 남아있게 되어 스레드 객체를 재사용 할 수 있다.

그리고 마지막으로 알아둬야 할 것이, WaitForSingleObject 함수이다.

역할은 Sleep과 동일하지만, 이 함수의 첫 번째 인자에 있는 스레드가 사용할 수 있게 될 때까지 기다리는 것이다.

Sleep은 스레드를 멈추는 역할밖에 못하지만, WaitForSingleObject는 특정 시간동안 이벤트를 감지할 수 있습니다.

WaitForSingleObject 의 두 번째 인자에는 밀리세컨드 단위의 시간이 들어가는데, INFINITE가 들어가면 스레드가 끝날때까지 기다리게 됩니다.

만약 구현이 된다면 아래와 같은 구조가 될 것이다.

  pThread = AfxBeginThread(ExportVVF, &arg1, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED); //Make Thread with suspension
pThread->m_bAutoDelete = FALSE; //if this thread will be end, object will not destory this thread.
  pThread->ResumeThread(); //Begin Thread
WaitForSingleObject(pThread->m_hThread, INFINITE);
::GetExitCodeThread(pThread->m_hThread, &returnvalue); //Get ExitCode from thread.


써놓고 보니 정신없네;;;
[출처] AfxBeginThread 사용법|작성자 큐티뽀

'Program Visual C++' 카테고리의 다른 글

YUV to RGB ...  (0) 2011.08.10
쓰레드 사용 예제?? AfxBeginThread, CreateThread, _beginthreadex  (0) 2010.10.10
Microsoft Platform SDK  (0) 2009.02.25
RichEdit 관련  (0) 2008.02.29
VC++ UNICODE Build - Configuration  (0) 2007.07.12

Microsoft Platform SDK

Program Visual C++ 2009. 2. 25. 09:33 Posted by HisPark

■ Microsoft Platform SDK install


1. 서론
   Microsoft Visual Studio는 Windows OS를 제어하기 위한 각종 api 함수를
   헤더파일과 함께 라이브러리로 제공한다.
   하지만, Microsoft Visual Studio는 개발에 필요한 기본적인 api는 제공하지만,
   그 이상의 api를 사용하기 위해서는 Platform SDK를 설치해야 한다.
   (예를 들어서, 툴팁 도움말 중, 각이 동그란 풍선도움말)

   ※ (추가)
   Microsoft에서는 매번 새로운 OS 또는 패치가 이루어 졌을때 상황에 따라서
   해당 부분을 개발자가 지원 할 수 있도록 library를 제공하는데 이게 Platform SDK입니다.
   예를 들면 XP sp2가 나오면서 방화벽등과 관련된 부분을 어플리케이션이 제어 할 수 있도록
   지원하기 위해서 2004년도에 "Microsoft Platform SDK for Windows XP SP2"을 지원했었죠.

   2006년 8월 현재 가장 최신의 SDK는 Windows® Server 2003 R2 Platform SDK입니다.
   반면에 VisualStudio 6.0에서 지원가능한(공식) SDK는 "February 2003 SDK"이며
   XP SP2 SDK보다도 이전에 발표된 SDK입니다.

   Platform SDK-2003 February (Visual Studio 6.0 last support)
   Platform SDK-2004 Edition (Windows XP SP2)
   Platform SDK-2005 April (Windows Server 2003 SP1)
   Platform SDK-2006 March (Windows Server 2003 R2)


2. 다운로드
     http://www.microsoft.com/downloads/ 에 접속해서, "platform sdk"로 검색하면,
     아래와 같은 링크가 검색된다.

     검색이 잘 되지 않으면, 아래 링크로 한번에 찾아간다.
     (아래 링크는 수시로 변경될 수 있는 링크이다.)
     http://www.microsoft.com/downloads/details.aspx?FamilyID=a55b6b43-e24f-4ea3-a93e-40c0ec4f68e5&DisplayLang=en

     Windows Server 2003 용이지만, 2000, XP 등에 설치해도 된다.
  
     위 링크를 클릭하면, 다운로드 페이지가 출력되는데,

     스크롤을 내리다 보면, 아래와 같은 다운로드 버튼이 나타난다.
     인텔(intel)계열 CPU를 사용한다면, PSDK-x86.exe 을 다운받으면 된다.

PSDK-x86.exe 은 1M 크기의 작은 파일이다. 클릭하면, 온라인을 통해 실시간으로 다운받으며 설치된다.

'Program Visual C++' 카테고리의 다른 글

쓰레드 사용 예제?? AfxBeginThread, CreateThread, _beginthreadex  (0) 2010.10.10
AfxBeginThread 사용법?  (0) 2009.05.05
RichEdit 관련  (0) 2008.02.29
VC++ UNICODE Build - Configuration  (0) 2007.07.12
ActiveX 보안관련 설정  (0) 2007.05.25