OpenSSL 관련 자료

 

> Linux Journal - An Introduction To Openssl Programming.pdf

> Openssl Command-Line Howto.pdf

> OpenSSL.pdf

 

 

OpenSSL.pdf

 

Linux Journal - An Introduction To Openssl Programming.pdf

 

Openssl Command-Line Howto.pdf

블로그 이미지

맨오브파워

한계를 뛰어 넘어서..........

,
#include "stdio.h"
#include "string.h"

#include "openssl/bio.h"
#include "openssl/ssl.h"
#include "openssl/err.h"

int password_callback(char *buf, int size, int rwflag, void *userdata)
{
    /* For the purposes of this demonstration, the password is "ibmdw" */

    printf("*** Callback function called\n");
    strcpy(buf, "ibmdw");
    return 1;
}

int main()
{
    SSL_CTX *ctx;
    SSL *ssl;
    BIO *bio, *abio, *out, *sbio;

    int (*callback)(char *, int, int, void *) = &password_callback;

    printf("Secure Programming with the OpenSSL API, Part 4:\n");
    printf("Serving it up in a secure manner\n\n");

    SSL_load_error_strings();
    ERR_load_BIO_strings();
    ERR_load_SSL_strings();
    OpenSSL_add_all_algorithms();

    printf("Attempting to create SSL context... ");
    ctx = SSL_CTX_new(SSLv23_server_method());
    if(ctx == NULL)
    {
        printf("Failed. Aborting.\n");
        return 0;
    }

    printf("\nLoading certificates...\n");
    SSL_CTX_set_default_passwd_cb(ctx, callback);
    if(!SSL_CTX_use_certificate_file(ctx, "certificate.pem", SSL_FILETYPE_PEM))
    {
        ERR_print_errors_fp(stdout);
        SSL_CTX_free(ctx);
        return 0;
    }
    if(!SSL_CTX_use_PrivateKey_file(ctx, "private.key", SSL_FILETYPE_PEM))
    {
        ERR_print_errors_fp(stdout);
        SSL_CTX_free(ctx);
        return 0;
    }

    printf("Attempting to create BIO object... ");
    bio = BIO_new_ssl(ctx, 0);
    if(bio == NULL)
    {
        printf("Failed. Aborting.\n");
        ERR_print_errors_fp(stdout);
        SSL_CTX_free(ctx);
        return 0;
    }

    printf("\nAttempting to set up BIO for SSL...\n");
    BIO_get_ssl(bio, &ssl);
    SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
    
    abio = BIO_new_accept("4422");
    BIO_set_accept_bios(abio, bio);

    printf("Waiting for incoming connection...\n");

    if(BIO_do_accept(abio) <= 0)
    {
        ERR_print_errors_fp(stdout);
        SSL_CTX_free(ctx);
        BIO_free_all(bio);
        BIO_free_all(abio);
        return;
    }

    out = BIO_pop(abio);

    if(BIO_do_handshake(out) <= 0)
    {
        printf("Handshake failed.\n");
        ERR_print_errors_fp(stdout);
        SSL_CTX_free(ctx);
        BIO_free_all(bio);
        BIO_free_all(abio);
        return;
    }

    BIO_puts(out, "Hello\n");
    BIO_flush(out);

    BIO_free_all(out);
    BIO_free_all(bio);
    BIO_free_all(abio);

    SSL_CTX_free(ctx);
}
블로그 이미지

맨오브파워

한계를 뛰어 넘어서..........

,

Visual Studio관련 다운로드
(서비스팩,재배포,Platform SDK,Windows SDK,DirectX SDK)


Microsoft Download 링크입니다.

아래 링크는 자주 바뀌므로 링크가 없을시는 이름으로 검색하시면 됩니다.

64-bit 모드는 x86페이지를 따라가서 받자. 페이지가 너무 길어짐;;

64-bit 모드(IA64, X64)에 관해서


 

Microsoft Windows SDK Blog

Windows SDK MSDN Developer Center
Windows SDK -> Platform SDK + .Net로 이름이 변경됨.

DirectX Developer Center


※ ATL관련 긴급보안 업데이트 관련 내용은 따로 정리했음. (2003~2008 sp1까지 해당됨)
Visual Studio ATL Security Update

VC 9.0(VS2008)

설치 순서 (SP1을 SDK보다 먼저 깔면 CRT라이브러리가 최신버젼으로 적용안됨)
SDK -> SP1 -> ATL

Windows® SDK for Windows Server® 2008 and .NET Framework version 3.5
- Windows Server® 2008와 .Net3.5를 위한 최신 버젼(2009년 4월 30일 기준으로 window7용 sdk가 나왔지만 아직은 beta)

Microsoft Visual Studio 2008 서비스 팩 1(iso)

MSDN Library for Visual Studio 2008 SP1 (2008년 12월 버전)

Microsoft Visual C++ 2008 SP1 재배포(Redistributable) 가능 패키지(x86)

Windows® SDK for Windows Server® 2008 and .NET Framework version 3.5(2008-05-02) 설치목록


VC 8.0(VS2005)

Windows® Server 2003 R2 Platform SDK Full Download
- 이버젼 이후로 Windows SDK로 변경, 2003(마지막),2005지원

Microsoft® Windows® Software Development Kit Update for Windows Vista - 2005 sp1이상

Microsoft® Visual Studio® 2005 Team Suite 서비스 팩 1


Microsoft Visual C++ 2005 SP1 재배포(Redistributable) 가능 패키지(x86) - 2.6MB

Windows® Server 2003 R2 Platform SDK(2006-03-15) 설치목록


2005제거시 맨마지막에 뜨는 정리하라는 메세지!!



VC 6

Platform SDK february 2003
VC6 지원 마지막 버젼

DirectX SDK : DirectX 9.0 SDK Update - (Summer 2004)
VC6 지원 마지막 버젼

Visual Studio 6.0 Service Pack 6

Visual Studio 6.0 Service Pack 5 - Processor Pack을 깔기위해선 서비스팩 5가 필요함

Processor Pack -  인텔의 MMX 함수를 사용하기 위해 꼭 깔아야 한다. 코덱등의 작업을 하려면 필수.

Microsoft Visual C++ 6 배포

Platform SDK february 2003 설치목록


참고
최근 Microsoft® Windows® Software Development Kit (MS Windows SDK) 릴리즈 기간에 대한 상념

블로그 이미지

맨오브파워

한계를 뛰어 넘어서..........

,


알툴바를 아시는지요? Internet Explorer 로 인터넷을 서핑할 때 마우스 오른쪽 버튼을 이용하여 키보드 사용을 최소화할 수 있도록 도와주는 툴입니다. 마우스의 동작을 인식하는 일명 Gesture 기능이지요.
 
이제 Visual Studio 에서도 이 기능을 사용할 수 있습니다.
VSGesture 는 Visual Studio 에서도 마우스의 동작을 인식하여 명령을 할 수 있습니다.

 
VSGesture v1.0
 


다운로드(Download)

이 링크에서 다운로드 받으십시오.

VSGesture 는 Visual Studio Gallary 사이트에서도 찾을 수 있습니다.
 

 
사용방법 : 코드 에디터에서 마우스 오른쪽 버튼을 클릭하고 동작을 그린다!
 
[그림1] VSGesture 실행 화면
 
설치 환경
l Windows Vista 이상
l .NET Framework 3.5 SP1
l Visual Studio 2008 / 2005
 
주요 기능
l 문서 이동
l 빌드
l 디버그
l 문서 제어
 
 
잠깐! VSGesture 는 Windows Vista 이상을 지원합니다.
 
Windows XP 또는 Windows Server 2003 사용자는 아래의 구성 요소를 다운로드 받아야 합니다. 단, 반드시 순서대로 설치하셔야 합니다.
 
Microsoft Windows XP Tablet PC Edition Software Development Kit 1.7
 
Microsoft Windows XP Tablet PC Edition 2005 Recognizer Pack
 
 
 
마우스 동작 사용법
 


 
편리한 VSGesture Visual Studio 와 함께 즐프하세요.


 

블로그 이미지

맨오브파워

한계를 뛰어 넘어서..........

,

배포시에는 Dependency Walker(depends.exe)와 같은 도구를 사용하여 종속 DLL의 목록을 확인한다. 또한 2005이상의 VS(Visual Studio)는 manifest를 꼭 확인해서 사용한 dll과 버전을 확인해야한다.

VC++ Library
그림 1(VS2005 기준)

그림은 VS2005를 기준으로 하고 있지만 다른 버젼도 위와 같은 규칙으로 명명되고 있다. xx는 각각의 버전을 나타내며 플랫폼 별로 x86,ia64,x64용이 따로 있다. u는 Unicode버전을 나타내고 m은 managed code를 사용했을때 사용되며 배포시 .NET Framework이 필요하다. 배포폴더에 manifest가 존재하면 같이 배포한다.

참고
Visual C++ Libraries as Shared Side-by-Side Assemblies - MSDN

접기

64-bit 모드(IA64, X64)에 관해서

X86: 우리가 흔히 알고 있는 IA32 명령어 기반의 프로세서를 말한다.

IA64(EPIC instruction set): 인텔 Itanium 프로세서부터 채용된 새로운 명령어 집합. 기존 IA32와 호환이 되지 않는다. EPIC(Explicitly Parallel Instruction Computing) instruction set을 가지며, 많은 차이점이 있겠지만, predicated instructions을 지원한다는 것과 최소 6개의 floating point unit은 기억할만하다.

X64: AMD Opteron 프로세서부터 채용되었고, AMD64, Intel64(EM64T)으로 소개되었지만, 지금은 X64로 보통 부른다. IA32를 64-bit을 지원하기위해 확장한 것으로, IA32와 완전한 호환을 가지는 Compatibity mode와 64-bit mode를 지원한다. 우리가 흔히 말하는 64-bit 모드이다. 

- 64-bit mode에서는 명령어에 8-bit REX prefix를 붙여서, 64-bit 레지스터를 사용할 수 있다. 또한, 64-bit mode에서는 레지스터 개수도 기존의 8개에서 16개로 다음과 같이 늘어났다.
   - Long mode - Compatibility mode: eax, edx, exc, ebx, esi, edi, esp, ebp
   - Long mode - 64-bit mode: rax, rdx, rxc, rbx, rsi, rdi, rsp, rbp, r8,r9,r10,r11,r12,r13,r14,r15

- AMD64에서는 Operating mode로서 총 5개가 지원된다.
   - Long mode - Compatibility mode
   - Long mode - 64-bit mode
   - Legacy mode - Protected mode
   - Legacy mode - Virtual 8086 mode
   - Legacy mode - Real mode

- AMD64의 어드레스는 레지스터 값은 64bit으로 부호확장되어 보이며, 현재는 다음과 같은 범위를 가진다.
 - physical address: 1TB (40-bit)
 - virtual address: 256TB (48-bit) : 부호확장이 되었으므로, 유효한 virtual address는 다음 두 영역으로 된다.
   - 0x0 ~ 0x00007FFF_FFFFFFFF
   - 0xFFFF8000_00000000 ~ 0xFFFFFFFF_FFFFFFFF

참고
http://blog.naver.com/purnnam1/60065549452

접기


컴파일러와 라이브러리의 버젼을 나타내는 매크로

Predefined Macros - MSDN

_MSC_VER(MS 컴파일러)

  Visual Studio 4.0  1000
  Visual Studio 5.0  1100
  Visual Studio 6.0  1200
  Visual Studio .NET 2002  1300
  Visual Studio .NET 2003  1310
  Visual Studio 2005  1400
  Visual Studio 2008  1500

_MFC_VER(MFC 버젼)

 Visual Studio 6.0   0x0600
 Visual Studio .NET 2002   0x0700
 Visual Studio .NET 2003  0x0710
 Visual Studio 2005  0x0800
 Visual Studio 2008  0x0900

_ATL_VER(ATL 버젼)

 Visual Studio 6.0   0x0300
 Visual Studio .NET 2002   0x0700
 Visual Studio .NET 2003  0x0710
 Visual Studio 2005  0x0800
 Visual Studio 2008  0x0900


VC 6 이하(~ VS6)
VC6관련 DLL은 98이후부터는 운영체제에 포함되어 있다. 그러므로 현재는 배포시에 거의 문제될게 없다.

참고
ActiveX 배포를 위한 cab파일(MS) - inf파일에 링크를 추가해준다.
Vcredist.exe로 Visual C++ 응용 프로그램용 최신 런타임 구성 요소가 설치된다 - MSDN고객지원

VC 7.1(VS 2003)
VC7.1관련 DLL은 최신 운영체제라고 해서 더는 기본 내장을 해주지않기 때문에 응용 프로그램이 알아서 자기 디렉터리나 윈도우 시스템 디렉터리에다 구비해야 한다.



VC 8이후(VS 2005~)

Side by Side Asembly
2005부터는 side by side asembly라는 기술이 도입되어 VC관련 라이브러리들이 Windows 디렉토리 밑에 WinSxS (Windows Side-by-Side)라는 공유 폴더(native assembly cache)로 관리된다. side by side asembly는 DLL 충돌문제를 해결해서 각각의 어플리케이션에게 독립적인 DLL환경을 제공하기 위한것으로 여러버젼의 DLL들이 등록될수 있다. 복잡한 이과정을 간단하게 해결하는 방법으로 VC8부터는 재배포 패키지(Redistributable Package)라는 배포용 설치파일이 도입되어 공용 라이브러리를 자동으로 설치/등록해준다. 또한 프로젝트에서 자동 생성해주는 Manifest Flie에 사용된 DLL과 버전이 자동으로 입력되니 배포시는 꼭 확인하도록 한다.
프로그래머나 사용자입장에선 관련 DLL을 포함만 하면 되는 기존 작업과 달리 설치파일이 하나 더생겼으니 귀찮은 작업이지만 최신 운영체제의 기본 관리 방법이기도 하고 .Net의 기술과도 무관하지 않으니 지금 정리하도록 하자.


최신 라이브러리를 Manifest에 기술하기(VC9)
배포방법을 알아보기 전에 알아두어야 할사항이 있다. VC9는 VC8과 달리 sp1같은 최신 라이브러리를 개발자PC에 설치했다고 해도 프로젝트가 최신라이브러리를 사용한다고 명시해주지 않으면 기존라이브러리를 기본으로 사용하므로 주의해야한다. 이것은 개발자가 sp1을 설치했어도 프로젝트는 기존 DLL버전을 사용하므로 배포시 sp1용 재배포 패키지를 사용하면 제대로 실행될 수 없음을 나타낸다. 방법은 아래와 같다.

'_BIND_TO_CURRENT_VCLIBS_VERSION'를 프로젝트 설정에서 선언해준다.
-> stdafx.h의 상단에 #define으로 입력해도 일반적인 프로젝트에선 상관없지만 프리컴파일드 헤더를 사용안하거나 외부라이브러리가 프로젝트에 미리 세팅되었을 경우 두개의 버전을 중복 사용하는 경우가 발생할 수 있으므로 프로젝트 설정에서 선언하길 권장한다. 이값은 CRT,MFC,ATL,OPENMP 4개의 '_BIND_TO_CURRENT...' 선언을 다 쓰겠다고 선언하는것이고 _BIND_TO_CURRENT_VCLIBS_VERSION의 기본값은 0으로 세팅되어있다.

접기

2008에서 MFC프로젝트 생성시 자동으로 생성해주는 Manifest file이다. Manifest File의 종류는 External(외부)와 Internal(내부)가 있는데 VC프로젝트 기본설정으로 컴파일시 Internal로 Exe파일에 자동으로 포함된다. 위치는 파일의 거의 마지막 부분이고 일반적인 텍스트로 아래와 같이 보이므로 메모장 등으로 확인해보자.
01.<P style="MARGIN: 0cm 0cm 0pt" class=MsoNormal>
02.<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
03.  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
04.    <security>
05.      <requestedPrivileges>
06.        <requestedExecutionLevel level="asInvoker" uiAccess="false"></requestedExecutionLevel>
07.      </requestedPrivileges>
08.    </security>
09.  </trustInfo>
10.  <dependency>
11.    <dependentAssembly>
12.      <assemblyIdentity type="win32" name="Microsoft.VC90.CRT" version="9.0.21022.8" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"></assemblyIdentity>
13.    </dependentAssembly>
14.  </dependency>
15.  <dependency>
16.    <dependentAssembly>
17.      <assemblyIdentity type="win32" name="Microsoft.VC90.MFC" version="9.0.21022.8" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"></assemblyIdentity>
18.    </dependentAssembly>
19.  </dependency>
20.  <dependency>
21.    <dependentAssembly>
22.      <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="x86" publicKeyToken="6595b64144ccf1df" language="*"></assemblyIdentity>
23.    </dependentAssembly>
24.  </dependency>
25.</assembly>
26.</P>
2008의 기본 Dll버전은 9.0.21022.8이고 sp1은 9.0.30729.1, ATL 관련 보안업데이트시 9.0.30729.4148버전을 사용한다.

참고

외부 Manifest와 내부 Manifest의 적용 순서

접기


참고

응용 프로그램 재배포 및 특정 라이브러리에 바인딩 - MSDN

최신 라이브러리를 메니페스트에 기술하기


배포방법
그림1과 참고에 MSDN링크가 2005의 공용DLL 목록과 설명이다. side by side asembly로 인해 배포문제가 좀 복잡해져서 depends 만을 확인해서 관련 DLL을 포함한다고 제대로 실행된다는 보장을 받을 수 없게되었다. 일반적인 방법과 재배포 패키지를 사용하는 방법을 알아보자.

1. 정적 라이브러리(Static Library)를 사용한다.
실행파일이 커지긴 하나 제일 간단하다. MFC 라이브러리를 사용시는 MFC라이브러리를 정적으로 포함하면 CRT도 자동으로 /MT로 변경된다. 용량은 기본 MFC 다이얼로그 프로젝트가 52k정도에서 308k 정도로 커진다.
ATL과 OPENMP까지 사용한다면 웹에서 배포되는 ActiveX 같은 상황이면 용량때문에 고민해봐야할 문제이고 정적라이브러리도 동적라이브러리와 똑같다고는 하지만 몇가지 버그가 있으므로 주의하자.

참고
MFC Static으로 소켓사용시..

2. Manifest를 참조해서 기본 DLL을 배포한다.(Private Assembly)
배포방법이 바뀌었다곤 하나 관련 DLL을 포함해서 배포할수도 있다. VS의 설치폴더에 있는 공용DLL(Private Assembly)을 같이 배포하면 된다. 우선 Manifest로 사용한 DLL을 확인한후 "..\Microsoft Visual Studio X\VC\redist\"에서 관련 DLL(그림1참고)을 프로젝트 폴더에 포함한다. 이방법도 쉬운편이긴 하나 3MB정도의 크기인 재배포 패키지에 비하면 사용하는 라이브러리가 많을 수록 용량이 너무 큰편이다.(기본 CRT와 MFC라이브러리만 4.76MB - 2008sp1 기준)

3. 인스톨쉴드(Install Shield), 설치 프로젝트를 이용해서 재배포 패키지가 자동으로 설치되게 한다.
 -> 모든 프로젝트를 이렇게 만들긴 좀 귀찮다;;

4. .Net Framework(최신)를 설치한다.
.Net Framework를 설치하면 CRT관련 DLL만 같이 설치된다.(fx 3.5설치시 8.0과 9.0이 같이 설치됨)
managed로 컴파일했다면 .Net Framework는 필수이므로 고민할 문제가 아니지만 용량이 100메가도 훨씬 넘는다..;;

5. 재배포 패키지 - 아래에서 따로 설명한다.

위 방법 외에도 몇가지가 더 있으며 아래링크를 참조하기 바란다.
RedistributingVisualCppRunTimeLibrary
Bootstrapper for the VC++ 2005 Redists (with MSI 3.1) - codeproject

재배포 패키지(Redistributable Package)
재배포 패키지는 Windows Installer 3.1을 필요로 하는 인스톨 파일이다. 한번 실행하기만 하면 자동으로 설치되지만 사용자 입장에선 불편한 사항이다. 하지만 Windows Installer의 Command line을 이용해서 몰래설치하는 방법이 있다. 이를 이용해서 런처형식의 프로그램을 만들면 Windows Installer 3.1의 설치유무와 재배포 패키지 자동 설치를 하고 프로그램을 실행하게 할 수 있다. 좀더 범용적으로 사용하면 파일로 설치필요 설정값을 받아와서 COM관련 등록이나 웹배포시 ActiveX등록등을 자동으로 하게 만들수도 있다. 관련 소스가 정리되는 대로 블로그에 올리도록 하고 우선 VC6으로 재배포 패키지의 설치유무와 자동 실행하기 위한 코드를 설명하겠다.

1) 재배포 패키지 설치 유무 확인
재배포 패키지는 설치폴더에서 받거나(..\Microsoft Visual Studio X\SDK\v2.0\BootStrapper\Packages\vcredist_x86) 아래 링크를 통해 MS의 다운로드에서 받는다.

2-1) 일반 적인 인스톨러 사용처럼 추가/제거 목록에 표시되므로 레지스트리 값으로 확인할 수 있다.
"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\ProductCode"

2-2) MsiQueryProductState API를 이용해서 확인한다.
리턴값으로 INSTALLSTATE_DEFAULT인지만 확인하면 설치유무를 판단할 수 있다.

위 2개의 방법에서 모두 필요한 ProductCode는 아래와 같다.

Visual C++ 2005 runtime files

Visual C++ 2005 SP1 runtime files

Visual C++ 2008 runtime files

Visual C++ 2008 SP1 runtime files

위코드는 영문 버전이고 한글버전은 다르고 설치시 중복될수 있다. ProductCode와 추가/제거에 표시되는 이름외에 다른점은 없다. 참고로 2008 sp1 x86 한글버전은 {887868A2-D6DE-3255-AA92-AA0B5A59B874}이다.
Window7에서도 테스트 했음.

참고
How to detect the presence of the VC 8.0 runtime redistributable package
How to detect the presence of the Visual C++ 9.0 runtime redistributable package
NSIS로 VC8.0 Redistributables 체크방법
MsiQueryProductState를 통한 VC 2005 Redistribute 라이브러리 설치체크 방법


2) 재배포 패키지 몰래 설치하기(Command Line)
명령행으로 실행시 Windows Installer 로 만들어진 패키지는 /?로 명령어 종류를 볼수 잇다.

접기

Windows Installer V3.0.1.4001.5512 기준으로 캡쳐한화면이다.


접기


VS2005
VC2005의 경우는 재배포 패키지가 VS기본 폴더에 존재하는 설치파일과 웹에서 받은 파일이 좀 다른데 웹에서 받은 재배포 패키지의 경우 압축이 한번더 되어있어서 인자값 설정 방법이 다르다. 또한 압축이 몇번에 걸쳐 되어있으므로 한글로 계정이 되어있어 한글 경로가 있을 경우 잘 설치가 안될수도 있다. 필자는 2008을 사용하므로 2005에 대한 사항은 관련 링크로 정확한 정보를 얻자.
How to perform a silent install of the Visual C++ 8.0 runtime files (vcredist) packages
- VS기본 폴더에 포함된 재배포 패키지 설치
VC 8.0 런타임 (vcredist) 패키지 몰래 인스톨하기 - 웹에서 받은 재배포 패키지 설치(번역)
Visual C++ 2005 재배포 패키지가 설치안될때



VS2008
2008에서는
<full path>\vcredist_x86.exe /qb
<full path>\vcredist_x86.exe /qb!
<full path>\vcredist_x86.exe /q   -> 화면에 전혀 보이지 않음
위 3가지 방법중 선택해서 사용하면 되며 Vista이상의 경우는 /q로 설정해도 UAC가 보이므로 필자는 /qb!를 사용한다. 직접 사용해보고 판단하자.

참고
How to perform a silent install of the Visual C++ 2008 redistributable packages

99%'s Code
위 재배포 패키지 몰래설치하기 코드를 간단하게 정리했음.

1. 설치유무 판단후 재배포 패키지를 설치하고 원하는 파일을 실행한다.
01. // 2008 sp1
02.    CString csProduct = "{887868A2-D6DE-3255-AA92-AA0B5A59B874}";   
03.//{9A25302D-30C0-39D9-BD6F-21E6EC160475}
04.  
05.    INSTALLSTATE t = MsiQueryProductState(csProduct);
06.    if(INSTALLSTATE_DEFAULT != t)
07.    {
08.        AfxMessageBox("재배포 패키지를 설치하겠습니다.");
09. //    WinExec("vcredist_sp1_x86.exe /q",SW_SHOW);
10.        WinExec("vcredist_sp1_x86.exe /qb!",SW_SHOW);
11.        AfxMessageBox("설치 완료"); 
12. // xp에선 설치완료후 정확하게 뜨지만 Windows7에선 완료되지 않았는데 뜬다.
13.    }
14.    else
15.        AfxMessageBox("이미 설치됨");
16.     
17.    // 아래 레지스트리값의 유무로 판단할수도 있다.(win7에서도 똑같다.)
18.    //HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{887868A2-D6DE-3255-AA92-AA0B5A59B874}
19.     
20.    while(INSTALLSTATE_DEFAULT != MsiQueryProductState(csProduct))
21.        Sleep(30);
22.    WinExec("test.exe",SW_SHOW);    // 원하는 프로그램 실행
2. 제거
    WinExec("vcredist_sp1_x86.exe /qu",SW_SHOW);
    AfxMessageBox("제거 완료");


 

블로그 이미지

맨오브파워

한계를 뛰어 넘어서..........

,

- 벡터로 자료를 영구 보관시키고있슴

 - 마우스를 드래그한 범위를 선을 그림

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class LineDrawEx extends JFrame {
	
	public LineDrawEx(){
		setContentPane(new MyPanel());
		setSize(300,300);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setVisible(true);
	}
	
	class MyPanel extends JPanel{
		Point startP = null;
		Point endP = null;
		
		public MyPanel(){
			this.addMouseListener(new MyMouseListener());
		}
		
		class MyMouseListener extends MouseAdapter{
			public void mousePressed(MouseEvent e){
				startP = e.getPoint(); // 클릭한부분을 시작점으로
			}
			public void mouseReleased(MouseEvent e){
				endP = e.getPoint(); // 드래그 한부분을 종료점으로
				Graphics g = getGraphics();
				g.drawLine(startP.x, startP.y, endP.x, endP.y);
			}
		}
	}
	
	public static void main(String[] args) {
		new LineDrawEx();
	}
}

이렇게 하게되면 드래그를 통해서 선은 그려지나..... 영구 보존되진않는다. 화면에 변화생기면 지워진다.
 


벡터를 이용해서 영구적 자료 보관하면서 그리기
 
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Vector;

public class LineDrawEx extends JFrame {
	
	public LineDrawEx(){
		setContentPane(new MyPanel());
		setSize(300,300);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setVisible(true);
	}
	
	class MyPanel extends JPanel{
		Vector<Point> sv = new Vector<Point>(); // 시작
		Vector<Point> se = new Vector<Point>(); // 끝점
		
		public MyPanel(){
			this.addMouseListener(new MyMouseListener()); // 리스너
		}
		
		public void paintComponent(Graphics g){
			super.paintComponent(g); // 부모 페인트호출
			
			if(sv.size() == 0) // 벡터에 암것도없으면 리턴
				return;
			
			for(int i=0;i<sv.size();i++){ //벡터크기만큼
				Point sp = sv.get(i); // 벡터값을꺼내다
				Point ep = se.get(i);	
				g.drawLine(sp.x, sp.y, ep.x, ep.y);//그리다
			}
		}
		
		class MyMouseListener extends MouseAdapter{
			public void mousePressed(MouseEvent e){
				sv.add(e.getPoint()); // 클릭한부분을 시작점으로
			}
			public void mouseReleased(MouseEvent e){
				se.add(e.getPoint()); // 드래그 한부분을 종료점으로
				repaint(); // 다시그려라
			}
		}
	}
	
	public static void main(String[] args) {
		new LineDrawEx();
	}
}


기존 기능에서  마우스를찍고 드래그하는 위치를 보여주는 예쩨

 

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Vector;

public class LineDrawEx extends JFrame {
	
	public LineDrawEx(){
		setContentPane(new MyPanel());
		setSize(300,300);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setVisible(true);
	}
	
	class MyPanel extends JPanel{
		
		Point startP=null;
		Point endP=null;
		
		Vector<Point> sv = new Vector<Point>(); // 시작
		Vector<Point> se = new Vector<Point>(); // 끝점

		public MyPanel(){
			//리스너를 공통으로해야  변수들이 공유된다.
			MyMouseListener ml = new MyMouseListener();
			
			this.addMouseListener(ml); // 리스너
			this.addMouseMotionListener(ml);
		}
		
		public void paintComponent(Graphics g){
			super.paintComponent(g); // 부모 페인트호출
			
			if(sv.size() != 0){
				for(int i=0;i<se.size();i++){ //벡터크기만큼
					Point sp = sv.get(i); // 벡터값을꺼내다
					Point ep = se.get(i);	
					g.drawLine(sp.x, sp.y, ep.x, ep.y);//그리다
				}
			}
			if(startP != null)
				g.drawLine(startP.x, startP.y, endP.x, endP.y);				
		}
		
		class MyMouseListener extends MouseAdapter implements MouseMotionListener{
			public void mousePressed(MouseEvent e){
				startP = e.getPoint();
				sv.add(e.getPoint()); // 클릭한부분을 시작점으로
			}
			public void mouseReleased(MouseEvent e){
				se.add(e.getPoint()); // 드래그 한부분을 종료점으로
				endP = e.getPoint();
				repaint(); // 다시그려라
			}
			
			public void mouseDragged(MouseEvent e){
				endP = e.getPoint();
				repaint();
			}
			
			public void mouseMoved(MouseEvent e){
				
			}
		}
	}
	
	public static void main(String[] args) {
		new LineDrawEx();
	}
}

 

블로그 이미지

맨오브파워

한계를 뛰어 넘어서..........

,

- 4개의 값을 입력받고, 그것을 그래프로 나타내준다.

 

 

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
 
public class GraphicsObjectEx extends JFrame {
	Container contentPane; // 컨테이너 생성
	int[] data = {0,0,0,0}; // 차트의 값 저장배열
	int[] arcAngle = new int[4]; 
 
	Color[] color = {Color.RED, Color.BLUE, // 색상 
			  Color.MAGENTA, Color.ORANGE};
 
	String[] itemName = {"티아라", "소녀시대", // 비교대상 
			                  "FX", "카라"};
 
	JTextField[] tf  = new JTextField[4]; // 텍스트필드
	ChartPanel chartPanel = new ChartPanel(); // 차트패널
 
	public GraphicsObjectEx(){ // 생성자
		setTitle("아이돌 인기도");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		contentPane = getContentPane(); // 컨테이너 갯
		contentPane.add(new InputPanel(), BorderLayout.NORTH);
		contentPane.add(chartPanel, BorderLayout.CENTER);
		setSize(500,350);
		setVisible(true);
		drawChart(); // 차트 메소드 호출
	}
 
	void drawChart(){ // 차트를 그린다
		int sum=0; // 초기값 0
		for(int i=0;i<data.length;i++){ // 데이터 값만큼 루프
			data[i] = Integer.parseInt(tf[i].getText());
			sum+=data[i];
		}
		if(sum == 0) 
			return;
 
		for(int i=0;i<data.length;i++){ 
			arcAngle[i] = (int)Math.round((double)data[i]/(double)sum*360);
			chartPanel.repaint(); // 차트패널의 PAINT호출
		}
	}
 
	class InputPanel extends JPanel{ // 입력패널
		public InputPanel(){
			this.setBackground(Color.LIGHT_GRAY); //배경
 
			for(int i=0;i<tf.length;i++){ // 현 가진갯수만큼
				tf[i] = new JTextField("0", 5);
				tf[i].addActionListener(new MyActionListener()); //리스너
				add(new JLabel(itemName[i]));
				add(tf[i]);
			}
		}
	}
 
	class MyActionListener implements ActionListener{ //액션리스너
		public void actionPerformed(ActionEvent e){ //텍스트필드변화시
			JTextField t = (JTextField)e.getSource();
			int n;
 
			try{
				n = Integer.parseInt(t.getText());
			}
			catch(NumberFormatException ex){
				t.setText("0");
				return;
			}
			drawChart(); // 호출	
		}
	}
 
	class ChartPanel extends JPanel{ // 차트 표시 패널
 
		public void paintComponent(Graphics g){
 
			super.paintComponent(g);//부모 패인트호출
 
			int startAngle = 0;
 
			for(int i=0;i<data.length;i++){
				g.setColor(color[i]);
				g.drawString(itemName[i]+""+Math.round
			   (arcAngle[i]*100/360)+"%", 50+i*100,20);
			}
 
			for(int i=0;i<data.length;i++){
				g.setColor(color[i]);
				g.fillArc(150,50,200,200,startAngle,arcAngle[i]);
				startAngle = startAngle + arcAngle[i];
			}
		}
	}
 
	public static void main(String[] args) {
		new GraphicsObjectEx();
	}
}
블로그 이미지

맨오브파워

한계를 뛰어 넘어서..........

,

각 숫자는 3개이고 재각각 스레드에서 동작한다

 

 

import javax.swing.*;
import java.awt.*;

public class TimerThreadFrame extends JFrame{
	public TimerThreadFrame(){
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setLayout(new FlowLayout());
		
		JLabel la = new JLabel("0");
		la.setFont(new Font("Helvetica", Font.BOLD, 80));
		la.setHorizontalAlignment(JLabel.CENTER);
		add(la);
		
		JLabel la2 = new JLabel("50");
		la2.setFont(new Font("Helvetica", Font.BOLD, 80));
		la2.setHorizontalAlignment(JLabel.CENTER);
		add(la2);	
		
		JLabel la3 = new JLabel("100");
		la3.setFont(new Font("Helvetica", Font.BOLD, 80));
		la3.setHorizontalAlignment(JLabel.CENTER);
		add(la3);	
		
		setSize(500, 150);
		setVisible(true);
		
		TimerThread tid = new TimerThread(la,10);
		tid.start();
		
		TimerThread tid2 = new TimerThread(la2,100);
		tid2.start();
		
		Thread th3 = new Thread(new ThreadRunable(la3, 1000));
		th3.start();
		
	}
	
	public static void main(String[] args) {
		new TimerThreadFrame();
	}
}

class TimerThread extends Thread{
	JLabel a;
	int n,m;
	
	public TimerThread(JLabel a, int m){
		this.a = a;
		this.m = m;
		n = Integer.parseInt(a.getText());
	}
	
	public void run(){
		while(true){
			try{
				sleep(m);
			}catch(InterruptedException e){
				return;
			}
			n++;

			a.setText(Integer.toString(n));
		}
	}
}

class ThreadRunable implements Runnable{
	JLabel a;
	int n,m;
	
	public ThreadRunable(JLabel a, int m){
		this.a = a;
		this.m = m;
	}
	public void run(){
		while(true){
			try{
				Thread.sleep(m);
			}catch(InterruptedException e){
				return;
			}
			n++;

			a.setText(Integer.toString(n));
		}
	}
}
블로그 이미지

맨오브파워

한계를 뛰어 넘어서..........

,

Synchronized 키워드

- 한스레드만이 독점적으로 실행되어야 하는 부분(동기화 코드의) 표시하는 키워드

- 임계영역

- 메소드 전체 블럭

- 일부분 코드 블럭

 

모니터란? 객체를 독점적으로 사용할수 있는 권한

               모니터를 먼저 소유한 스레드가 몬티너 내놀때까지 다른스레드는 기다린다

 

동기화 객체

두개이상의 스레드 사이에 동기화 작업에 사용되는객체

 

동기화 메소드

- synchonized블럭 내에서만 사용해야됨

 

wait()

- Object 클래스가 가진 메소드이다.

- 다른 스레드가 notify() 불러줄떄까지 기다린다.

 

notify()

- wait()로 인해 대기중인 스레드 깨우고 RUNABLE을 만든다.

- 2개이상의 스레드가 대기중이라도 오직 한개의 스레드만 꺠워 RUNABLE한다.

 

notifyAll()

- wait()를 호출로 인해 대기중인 모든스레드를 깨워버린다.

 


 

스레드 동기화는 크리티컬 섹션 임계영역을 서로 상호 배제 해주는 것이다.

 

C와 약간 스타일은 다르지만... 유형은 비슷하다 볼수있다.

 


- 크리티컬 섹션 임계영역의 변수 SUM이 존재한다.

- 2개의 스레드가 1개의 변수를 공유하는것이다..

- Synchorinzed를 사용하지 않는다면 임계영역 상호배제가 이루어지지않는다.

 

동기화를 사용한 소스코드

public class SynchronizedEx {
	
	public static void main(String[] args) {
		
		// 동기화 객체 선언
		SyncObject obj = new SyncObject();
		
		//스레드 객체 선언
		Thread th1 = new WorkerThread("지연", obj); 
		Thread th2 = new WorkerThread("은정", obj);
		
		th1.start(); // 스레드 시작
		th2.start();
	}
}

class SyncObject{ // 동기화 클래스
	
	int sum=0; // 공유영역
	
	synchronized void add(){
		
		int n = sum; 
		Thread.currentThread().yield(); // 현재스레드 양보해라 값을더하는동안
		n+=10;
		sum = n; // sum을 덮어라 자기값으로	
		System.out.println(Thread.currentThread().getName() + " : " + sum);
	}
	
	int getSum(){
		return sum;
	}
}

class WorkerThread extends Thread{
	
	SyncObject sObj; // 동기화 객체 선언
	
	//생성자
	WorkerThread(String name, SyncObject sObj){
		super(name);
		this.sObj = sObj;
	}
	
	public void run(){
		int i=0;
		while(i<10){
			sObj.add(); // 동기화 덧셈호출
			i++;
		}
	}
}

동기화를 사용하지않은 소스코드
synchronized void add(){
를..........
void add() 로 바꿔주고
 
Thread.currentThread().yield(); 를 사용하지않는다... 
 
그러면 스레드 동기화 기능이 사라짐 이렇게 테스트하면됨
 


동기화를  사용하지 않은 결과

 

EunJung : 20
EunJung : 30
EunJung : 40
JiYeon : 20
JiYeon : 60
JiYeon : 70
EunJung : 70
EunJung : 90
EunJung : 100
EunJung : 110
EunJung : 120
EunJung : 130
EunJung : 140
JiYeon : 80
JiYeon : 150
JiYeon : 160
JiYeon : 170
JiYeon : 180
JiYeon : 190
JiYeon : 200


동기화를 사용한 결과

 

JiYeon : 10
JiYeon : 20
JiYeon : 30
JiYeon : 40
JiYeon : 50
JiYeon : 60
JiYeon : 70
JiYeon : 80
JiYeon : 90
JiYeon : 100
EunJung : 110
EunJung : 120
EunJung : 130
EunJung : 140
EunJung : 150
EunJung : 160
EunJung : 170
EunJung : 180
EunJung : 190
EunJung : 200


 

Plus Alpha

 

위에 방법은 메소드로 특정 행동을 정의해놓은것을 불러서 하는 방식이고

변수에만 효과 주려면 이와 같디 하면된다.

 

 

예) buf라는 변수에 zz문자를 추가하는데, 동기화를 시켜서 추가하는

 

    synchronized (buf) {
        buf += "zz";
    }

블로그 이미지

맨오브파워

한계를 뛰어 넘어서..........

,

자바 스윙에서 JFrame, JPanel, JButton, JLabel, JToolBar, JMenu,

                   JDialog,FileDialog,JOptionPane등

 

움직이는 뱀 만들기





import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;

import java.awt.*;
import java.awt.event.*;
import java.util.Vector;

class HelpDialog extends JDialog{
	JTextField tf;
	
	public HelpDialog(JFrame f, String title, boolean modal){
		super(f, title, modal);
		setLayout(new FlowLayout());
//		add(new JLabel("이것은 뱀게임입니다."));
		tf = new JTextField(10);
		add(tf);
		JButton okBtn = new JButton("OK");
		add(okBtn);
		okBtn.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				setVisible(false);
			}
		});
		setSize(150,100);
	}
	int getValue(){
		String s = tf.getText();
		if(s.length() == 0)
			return -1;
		else{
			try{
				return Integer.parseInt(s);	
			}catch(NumberFormatException e){
				return -1;
			}
		}
	}
}
public class SnakeFrame extends JFrame{
	Thread snakeThread;
	GroundPanel p;
	
	public SnakeFrame(){
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 종료방법
		Container c = getContentPane();
		p = new GroundPanel(); // 메인패널 생성
		c.add(p, BorderLayout.CENTER);	
		setSize(400,400); // 창크기
		createToolBar(); // 툴바
		createMenu(); // 메뉴
		setVisible(true); // 표시여부
		p.requestFocus(); // 포커스 점령
		snakeThread = new Thread(p); // 스레드 초기화
		snakeThread.start(); // 시작
		
		ToolTipManager tt = ToolTipManager.sharedInstance(); // 툴팁 매니저 설저
		tt.setInitialDelay(5); // 툴 팁 나오는 시간 설정
		tt.setDismissDelay(2000); // 2초후 사라져라
	}
	
	public void createToolBar(){ // 툴바
		
		JToolBar tb = new JToolBar("Snake Controllar");
		tb.setFloatable(false); // 툴바 못움직이기 고정하기
		
		JButton suspendButton = new JButton("Suspend");
		suspendButton.setToolTipText("일시중지 합니다."); // 툴 설명쓰기
		tb.add(suspendButton);
		
		JButton resumeButton = new JButton("Resume");
		resumeButton.setToolTipText("이어하기 합니다."); // 툴 설명쓰기
		tb.add(resumeButton);
		
		tb.addSeparator(new Dimension(100,50));
		JButton plusButton = new JButton("Speed : +");
		
		tb.add(plusButton);
		
		JButton minusButton = new JButton("Speed : -");
		tb.add(minusButton);
		
		JButton helpButton = new JButton("HELP");
		tb.add(helpButton);
		
		
		getContentPane().add(tb,BorderLayout.NORTH);
		
		suspendButton.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				p.suspend();
				p.requestFocus();
			}
		});
		
		resumeButton.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				p.resume();
				p.requestFocus();
			}
		});
		
		plusButton.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				p.speedUp();
				p.requestFocus();
			}
		});
		
		minusButton.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				p.speedDown();
				p.requestFocus();
			}
		});
		
		helpButton.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				
//				HelpDialog d = new HelpDialog( (JFrame)null, 
//				"help dialog", true); // TRUE로하면 MODAL,else:modaless
//				d.setSize(150,100);
//				d.setVisible(true);
//				
//				int n = d.getValue();
//				if(n > 0)
//					p.setDelay(n);
//				p.requestFocus();
				
				//한줄짜리 입력창
				String s = JOptionPane.showInputDialog("Delay값을 입력하세요.");
				int n = Integer.parseInt(s);
				if(n > 0)
					p.setDelay(n);
				p.requestFocus();
				
			}
		});
	}
	
	public void createMenu(){ // 메뉴 등록
		JMenuBar mb = new JMenuBar();
		JMenu fileMenu = new JMenu("파일");
		JMenuItem item1 = new JMenuItem("Thread Resume");
		JMenuItem item2 = new JMenuItem("Thread Suspend");
		JMenuItem item3 = new JMenuItem("Thread Kill");
		JMenuItem item4 = new JMenuItem("Change Background");
		
		mb.add(fileMenu); // 메뉴바에 메뉴를붙여라
		
		fileMenu.add(item1); // 메뉴에 아이템을붙여라
		fileMenu.add(item2);
		fileMenu.addSeparator(); // 줄을 그어라
		fileMenu.add(item3);
		fileMenu.add(item4);
		this.setJMenuBar(mb);
		
		item1.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				p.resume();
			}
		});
		
		item2.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				p.suspend();
			}
		});
		
		item3.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				int res = JOptionPane.showConfirmDialog(
				null, "정말로 뱀을 잡을껍니까?","END?",JOptionPane.YES_NO_OPTION);
				
				if(res == JOptionPane.CLOSED_OPTION || 
						res == JOptionPane.NO_OPTION) // 클로즈를 눌럿다면..
					return;
				else
					snakeThread.interrupt(); // 인터럽트날려죽인다
			}
		});
		
		item4.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				p.suspend();
				
				//파일 다이얼로그 불러오기
				JFileChooser chooser = new JFileChooser();
				FileNameExtensionFilter filter = new FileNameExtensionFilter
				("JPG & GIF", "gif", "jpg");
				chooser.setFileFilter(filter); // 파일필터 지정
				chooser.showOpenDialog(null); 
				String path = chooser.getSelectedFile().getPath(); // 파일 경로 가져와라
				p.setImage(new ImageIcon(path).getImage());
								
				p.resume();
			}
		});
	}
	
	class GroundPanel extends JPanel implements Runnable{
		private boolean suspendFlag = false; // true:suspend
		
		final static int LEFT=0;
		final static int RIGHT =1;
		final static int UP = 2;
		final static int DOWN = 3;
		
		int delay=200;
		
		int direction; // 뱀의 방향
		
		Image img; // 이미지 객체
		
		SnakeBody snakeBody; // 스네이크 객체
		
		public GroundPanel(){
			setLayout(null);
			snakeBody = new SnakeBody(); // 생성자 호출
			snakeBody.addin(this); // 현객체 뱀에 추가

			direction = LEFT;
			this.addKeyListener(new MyKeyListener()); // 리스너 지정
			ImageIcon icon = new ImageIcon("images/back.jpg");
			img = icon.getImage(); // 아이콘을 이미지 객체로 가져옴
			
		}
		
		public void setImage(Image img){ // 배경 변경
			this.img = img;
			repaint();
		}
		
		public void paintComponent(Graphics g){
			super.paintComponent(g); // 부모 페인트 호출
			g.drawImage(img, 0,0, getWidth(), getHeight(), null); // 그림을 그려라 
		}
		
		public void run(){ // 스레드 수행 함수
			
			while(true){
				try{
					checkSuspend(); // 잠자는시간이면 띵겨라
					Thread.sleep(delay);
					snakeBody.move(direction); // 방향대로 움직여라
				}catch(InterruptedException e){
					return; // 만약 리턴이없다면 죽이질못한다
				}
			}
		}	
		
		synchronized void checkSuspend(){
			if(suspendFlag == false){
				return;
			}
			else{
				try{
					wait();
				}catch(InterruptedException e){
					return;
				}
			}
		}
		
		void setDelay(int n){
			delay = n;
		}
		
		void speedUp() {
			if(delay < 10)
				return;
			delay = delay / 2;
		}
		
		void speedDown(){
			delay = delay * 2;
		}
		
		void suspend(){ // 중단
			suspendFlag = true;
		}
		
		synchronized void resume(){ // 재개
			suspendFlag = false;
			notify();
		}
		
		class MyKeyListener extends KeyAdapter{ // 이벤트리스너
			
			public void keyPressed(KeyEvent e){
				switch(e.getKeyCode()){
				
				case KeyEvent.VK_LEFT :
					direction = LEFT;
					break;
					
				case KeyEvent.VK_RIGHT :
					direction = RIGHT;
					break;
					
				case KeyEvent.VK_UP :
					direction = UP;
					break;

				case KeyEvent.VK_DOWN :
					direction = DOWN;
					break;
				}
			}
		}
	}
	
	class SnakeBody{
		Vector<JLabel> v = new Vector<JLabel>();
		ImageIcon icon = new ImageIcon("images/head.jpg"); // 뱀 사진
		public SnakeBody(){
			for(int i=0;i<10;i++){ // 10개의 뱀머리 
				JLabel la = new JLabel(icon);
				la.setSize(20,20);
				la.setToolTipText("전 뱀입니다."); // 마우스 올리면 툴팁띄우기
				la.setLocation(100+i*20, 100);
				v.add(la);
			}
		}
		 
		public void addin(JPanel p){ // 꼬리에 추가
			for(int i=0;i<v.size();i++){
				p.add(v.get(i));
			}
		}
		
		public void move(int direction){ // 뱀이동
			for(int i=v.size()-1;i>0;i--){
				JLabel b = v.get(i);
				JLabel a = v.get(i-1);
				b.setLocation(a.getX(), a.getY());
			}
			
			JLabel head = v.get(0);
			
			switch(direction) { // 뱀 이동 알고리즘
			case GroundPanel.LEFT : 
				head.setLocation(head.getX()-10, head.getY());
				break;
				
			case GroundPanel.RIGHT : 
				head.setLocation(head.getX()+10, head.getY());
				break;
				
			case GroundPanel.UP : 
				head.setLocation(head.getX(), head.getY()-10);
				break;
				
			case GroundPanel.DOWN : 
				head.setLocation(head.getX(), head.getY()+10);
				break;
			}
		}
	}
	
	public static void main(String args[]){
		new SnakeFrame();
	}
}

 

블로그 이미지

맨오브파워

한계를 뛰어 넘어서..........

,