어떤 모듈(A 모듈 이라고 하자)에서 폼(B 폼 이라고 하자)을 호출한다고 할때
A 모듈에서 Private WithEvents Test As Form을 선언하고 Set Test=B 폼을 하면(일반 모듈에서는 WithEvents를 사용할 수 없다)
A 모듈에서 B 폼에 발생되는 모든 이벤트를 받을수 있다.
그러나 B 폼에서 사용자 정의 이벤트는 받을수 없다.

폼에서 사용자 정의 이벤트의 생성은 단순한다.
선언부에 Enent 이벤트명([인수]) 지정하고, ReaiseEvent 이벤트명을 하게되면 사용자 정의 이벤트를 발생시킨다.
이 이벤트는 Private WithEvents Test As Form로 선언하는 것이 아니라 Private WithEvents vSecurityForm As B 폼(폼명)
으로 선언되어야만 사용자 정의 이벤트를 받을수 있다.

만약 A 모듈에서 B폼을 vbModal(모달) 폼으로 호출했다면, A 모듈에서는 폼을 호출후에 실행 시점이 정지된다. 그러나 A 모듈에서는 이벤트는 받을수 있는 상태이므로 A 모듈에서 Private WithEvents vSecurityForm As B폼 으로로 선언하고,
Set vSecurityForm = B폼을 하였고, B폼에서 RaiseEvent로 사용자 정의 이벤트를 발생시키면 A 모듈에서 그 이벤트를 발생시킨다.(B폼이 종료 시점에 이벤트를 발생시켜주어, 폼의 값을 모듈에 전달하게 하는 이벤트를 발생후, 폼을 종료시키면, B폼에 있는 정보를 전달하는 것이 된다)

' 1폼 모듈(Form1)
Option Explicit

Private WithEvents FormEvent as Form
Private WithEvents UserEvent as Form2

Private Sub Form_Activate
    Set FormEvent = Form2
    Set UserEvent = Form2
    Form2.Show vbModal
End Sub

Private Sub FormEvent_Load()
End Sub

Private Sub UseEnent_EndForm(Byval Pass1 As String)
End Sub

' 2폼 모듈(Form2)
Option Explicit

Event EndForm(Byval Pass1 As String)

Private Sub Form_Unload(Cancel As Integer)
      RaiseEvent EndForm("Test")
      Unload Me
End Sub

● 타이머를 설정한다, 타이머 제거시 KillTimer를 사용한다
● 원형
 
선언 
SetTimer Lib "user32" (ByVal hwnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long
● 인수
hwnd ━ 타이머와 연관된 윈도우 핸들(호출될 쓰레드를 포함하는 윈도우),
nIDEvent ━ 0이 아닌 타이머 식별자
uElapse ━ 타임아웃 시간,밀리초
lpTimerFunc ━ 타임아웃시 호출할 콜백함수 TimerProc
● 복귀
성공 ━ hwnd가 Null이면 타이머 식별자,hwnd가 Null이 아니면 0이 아닌값
실패 ━ 0

'API > 선언' 카테고리의 다른 글

FlashWindowEx 함수  (0) 2011.10.28
FlashWindow 함수  (0) 2011.10.28
KillTimer 함수  (0) 2011.10.21
CopyMemory,MoveMemory,RtlMoveMemory 함수  (0) 2011.10.15
GetWindowDC 함수  (0) 2011.10.13

● 타이머를 제거한다
● 원형
 
선언
KillTimer Lib "user32" (ByVal hwnd As Long, ByVal uIDEvent As Long) As Long
● 인수
hwnd ━ 타이머와 연관된 윈도우 핸들
uIDEvent ━ 타이머 식별자로, hwnd이 Null이 아니면 SetTimer에 uIDEvent값, hwnd이 Null이면 타이머 식별자인
SetTimer의 반환값 지정
● 복귀
성공 ━ 0이 아닌값
실패 ━ 0

'API > 선언' 카테고리의 다른 글

FlashWindow 함수  (0) 2011.10.28
SetTimer 함수  (0) 2011.10.21
CopyMemory,MoveMemory,RtlMoveMemory 함수  (0) 2011.10.15
GetWindowDC 함수  (0) 2011.10.13
WM_ACTIVATE 윈도우 메세지  (0) 2011.10.13

타이머 컨트롤을 사용하려면 반드시 컨트롤이 필요하며, 컨트롤은 반드시 폼을 필요한다. 따라서 타이머 컨트롤을 사요하기 위해서는 폼이 필요하다. 그러나 일반 모듈 같은 곳에서 타이머를 사용하려면 방법이 없는 것은 아니다. API를 사용하여 타이머를 사용할 수 있다. SetTimer로 타이머를 작동시키고 KillTimer로 지정된 타이머를 삭제할수 있다.

다음은 소스이다.
'일반 모듈이다.
' 윈도우 없이 타이머를
Option Explicit

Public Declare Function KillTimer Lib "user32" (ByVal hWnd As Long, ByVal nIDEvent As Long) As Long
Public Declare Function SetTimer Lib "user32" (ByVal hWnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long

Public state As Boolean ' 타이머 종료 프로시저 호출 상태
Public ID As Long ' 타이머 ID

Sub main()
    ID = SetTimer(0&, 1000, 100, AddressOf TimerProc)
    Form1.Show
End Sub

' 타이머 프로시저
Public Sub TimerProc(ByVal hWnd As Long, ByVal uMsg As Long, ByVal idEvent As Long, ByVal dwTime As Long)
    Debug.Print state '
End Sub

다음은 폼 모듈이다.
Option Explicit

Private Sub Command1_Click()
    state = True
    KillTimer 0&, ID ' 타이머를 제거한다.
End Sub

여기서 폼 모듈은, KillTimer의 호출 여부를  확인 하기 위한 상태 변수를 지정하기 위함이다.
소스를 실행시키면 직접 실행창에 KillTimer의 호출 상태를 나타내는 State의 상태 값이 쭉 표시된다.
폼의 커맨드 버튼을 누름과 거의 동시에 State 상태 값이 출력되는 것이 정지되는 볼수 있다. 즉 타이머가 삭제된 것이다.

웹두레 사이트는 웹서핑,광고 메일,쪽지,SMS,추천인,이벤트,설문 등을 사용해 포이트를 적립하며, 1포인트는 4원의 가치가 있으며, 3000포인트 이상이되면 적립금 현금 신청을 하실수 있읍니다.


포인트 쌓기(인터넷 상에서 돈벌기 위해서는 한 순간에 큰돈을 벌수 있는 사이트 없읍니다. 광고야 그럴듯 하게 하지만은 막상 해보면 그렇치가 않습니다. 이 사이트도 마찬가지 입니다. 한 순간에 큰돈을 벌수는 없습니다. 다른  사이트들도 마찬가지 입니다. 인터넷 상에서 돈벌기 위해서는 꾸준하게 하시는것이 필요합니다.)

포인트 쌓기
서핑적립
상단 메뉴의 적립하기의 서핑적립을 클릭하시면 적립및 이벤트에 응모하실수 있읍니다.


위 메뉴를 클릭하여 나오는 페이지에서 오른쪽의 서핑 적립 바로 시작 버튼을 누르시면 광고 페이지의 상단에 아래 이미지가 표시되며 하단에 광고 페이지가 표시됩니다.

20초 동안 해당 웹페이지를 유지 하셔야 합니다. 팝업 창이 뜨는 경우 팝업창도 20초 동안 유지 하셔야 합니다.
해당 페이지가 포인트 적립이 되는 페이지라면, 초가 표시되는 위 또는 아래에 적립을 알리는 메세지가 표시되며, 20초 후에 적립에 되었다는 메시작 표시됩니다. 이때까지 웹페이지와, 팝업창을 유지 하셔야 합니다(팝업창이 있는 페이지 인 경우만) 
적립 외에 이벤트 기회가 제공된다는 메세지가 나오는대, 당첨되면 우정포인트 5포인트를 얻으실수 있읍니다. 우정 포인트는 하루에 1회이며, 여러번 당첨기회가 주어진다면 당첨 확률도 높아지갰죠.
적립이나, 당첨 기회가 주어졌으면 다음 페이지 버튼을 눌러 다음 페이지를 보실수 있읍니다.

한 줄 일상
상단 메뉴의 웹두레 프라자 메뉴를 클릭하면 나타나는 페이지에서 왼쪽 메뉴의 한 줄 일상 메뉴를 클릭하여

나타나는 웹페이지에서 한줄의 짧은 글을 작성하므로 하루 1포인트를 얻을수 있으며, 7일 연속 작성하셨다면 추가로 7포인트를 더 얻으실수 있읍니다.

간편 설문
상단 메뉴의 웹두레 프라자 메뉴를 클릭하면 나타나는 페이지에서 왼쪽 메뉴의 간편 설문 메뉴를 클릭하여 나타는 웹페이지에서 설문에 참가하므로 포인트를 적립할 수 있읍니다. 해당 설문은 마감되지 않은 설문이어야 하며, 적립 포인트는 해당 설문의 적립포인트에 표시되어 있읍니다.

추천인 적립
웹두레에서는 본인의 추천인을 민들레 회원이라고 하고, 본인의 하부 회원을 홀씨회원이라고 합니다. 홀씨회원의 서핑적립이나 제류 적립은 홀씨 회원의 추천인 즉 홀씨회원의 민들레회원에게 추가 적립됩니다. 서핑적립은 50%로, 제류적립은 10%로 적립됩니다
가입시 추천인란에 추천인이 적혀 있고, 가입 후에 메일 인증을 완료하시면
새로 가입하시는 분께는 30포인트가, 추천인에게는 20 포인트가 추가 적립됩니다

상당히 오래된 사이트입니다.

고로 믿을수 있읍니다. 잠시 생겼다 사라지는 그런 사이트가 아닙니다. 적립 사이트에는 그런 사이트가 많습니다.

다음 이미지는 제가 한달간 저릭한 웹두레 포인트입니다. 포인트당 4원이내가 4000원이내요.


다음 이미지는 환급자 명단의 일부 입니다. 웹두레 사이트에 가면 보실수 있읍니다.

● 메모리의 지정된 부분을 복사한다.
● 사용시 Type 데이타형 복사시에 Type데이타를 직접 사용하여도 된다, copymemory a,b,lenb(b)
● 원형

● 선언
CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
MoveMemory Lib "kernel32" Alias "RtlMoveMemory" (pDest As Any, pSource As Any, ByVal dwLength As Long) RtlMoveMemory Lib "kernel32" (hpvDest As Any, ByVal hpvSource As Long, ByVal cbCopy As Long)
● 인수
Destination ━ 복사받을 변수
Source ━ 복사할 변수
Length ━ 복사할 바이트 수

'API > 선언' 카테고리의 다른 글

SetTimer 함수  (0) 2011.10.21
KillTimer 함수  (0) 2011.10.21
GetWindowDC 함수  (0) 2011.10.13
WM_ACTIVATE 윈도우 메세지  (0) 2011.10.13
ReleaseDC 함수  (0) 2011.10.11

vb6에서는 클래스 상속이 없다.
그러나 인터페이스 구현은 가능하다.

소스로 예를 들어보겠다.
프로젝트를 생성 ActiveX Dll로 생성한다.
클래스에
달랑 메소드 명만 입력하고 코드는 입력하지 않는다.

Option Explicit

Public Sub TestInterface()
End Sub

접근자는 Public으로 입력해야 된다.

다음은 Exe프로젝트를 하나 추가한다.
그리고 참조에서 이전에 프로젝트명을 찾아 참조에 추가한다.
그리고 Exe 프로젝트에 클래스 모듈을 하나 추가하고
Implements를 사용해 이전의 프로젝트 클래스 메소드를 다시 구현한다.
상단의 콤보 박스에 클래스명과 메소드를 선택해도 관계없다.
Option Explicit

Implements clsInt

Private Sub clsInt_TestInterface()
    MsgBox "Class1"
End Sub

Public Sub test()
    Debug.Print "test"
End Sub

다음은 폼 모듈에 버튼 하나를 올리고
폼 모듈 소스에서 이전 프로젝트의 클래스에 대한 개체 변수를 생성하고
같은 프로젝트의 클래스에 개체를 생성해서 위의 개체 변수에 참조시켠 참조가 된다.
왜 인터페이스가 같기 때문이다.
그러면 개체변수.메소드를 호출하게 되면
현재 프로젝트에 구현된 인터페이스 프로시저가 호출된다.
Option Explicit

Private Sub Command1_Click()
    Dim b As clsInt ' 인터페이스 개체 변수 생성
    Set b = New Class1 ' 클래스 개체를 생성하여, 인터페이스 개체 변수에 할당
    b.TestInterface ' 인터페이스 메소드 호출하면, 인터페이스 개체 변수에 할당된 개체의 원래 클래스의 메소드가 호출된다.
    
    Dim c As Class1 ' 클래스 개체 변수 생성
    Set c = b ' 클래스 개체 변수에 인터페이스 개체 변수에 할당된 개체 할당
    c.test ' 개체의 클래스에 구현된 메소드 호출
End Sub

같은 형태의 메소드를 사용하는 클래스가 많은 경우, 이들을 효과적으로 관리하기 위해 인터페이스를 사용하므로
각 클래스에 코드는 다르지만 서로 같은 메소드 이름과 형식을 같게 되므로
서로 다른 클래스 개체라도  같은 방법으로 메소드를 호출하게 되므로, 루프를 돌리게된다던지 하는 방법으로 사용할
수 있다.

인터페이스 클래스와, 대상 클래스를 같은 그룹 프로젝트에 포함시키던지
따로 DLL을 만들어 참조하는 형태로 사용할 수 있다. 따로 DLL을 생성하면 후기 바인딩도 가능하다.

인터페이스를 상속하는 클래스가 있다고 할때, 인터페이스의 추가한 경우는 관계 없지만, 추가된 기능을 삭제한 경우에
는 클래스에서 DLL 생성시에 아래와 이미지와 같은 에러가 발생된다

이때는 프로젝트 속성에 구성요서 탭에 버전 호완성에서 호환성 없음으로 선택하고 DLL 생성할수 있으면 다시 이전의 호환성으로 선택하면 된다.
클래스는 어떤 개체를 생성하기 위한 틀이다.
인스턴스란 클래를 기본으로 생성한 개체를 말한다
인스턴스=실체=오브젝트=객체 같은 말이다.

상속이란 한 글래스가 다른 클래스에게 자신의 멤버를 물려주는거
여기에는 상속을 해주는 부모 클래스와, 상속을 받는 클래스 자식 클래스(또는 파생 클래스)가 있다.

InHerits는 기본 클래스를 지정한다.
MustInHerits는 해당 클래스는 인스턴스를 행성할수 없고, 이클래스를 상속한 자식 클래스의 인스턴스만 생성할수 있다. 이를 추상 클래스라고 한다.
NotInHeritable는 상속이 되지 않는 클래스를 말한다, 즉 자식 클래스를 만들수 없는 클래스이다. 이를 봉인 클래스라 한다.

Is-a 상속 관계는 A 클래스는 B클래스이다. 이런 상속 관계(명시적으로 클래스를 상속 한다는 것을 지정해야 한다)
has-a 상속 관계는 A 클래스는 B클래스를 포함한다.(명시적으로 클래스 상성을 지정하지 않고, 클래스 내에서 포함할 클래스의 개체를 생성하고,사용하는 것을 말한다)

개체를 참조시 개체 변수형이 부모 클래스 인경우에는 자식 클래스를  부모 클래스에 가능하나, 개체 변수형이 자식 클래스 형일 경우일 때, 부모 클래스를 자식 클래스에 할당하는 것은 불가능하다.

가상메소드: 자식 클래스들이 똑같은 메소드를 갖고 있으나 부모 클래스는 그 메소드가 없을 경우에,
수천개의 자식 개체를 생성했다고 가정 때,
가상 메소드가 없다면 일일이 자식 개체의 메소드를 호출해 주어야 한다.
그러나 가상 메소드를 사용한다면 간단하게 루프를 돌릴수 있다.
위에서도 말했듯이 자식 클래스는 부모 클래스형 변수에 참조 시킬수 있다라고 했다.
따라서 부모 클래스 변수의 배열을 선언하고, 생성한 자식 클래스의 개체를 참조시킨다.
그러나 아직 가상 메소드를 사용하지 않았기 때문에 자식 클래스에는 다 같은 이름으로 있는 메소드인데, 부모 클래스에는 그런 이름의 메소드가 없는 메소드를 호출하려면, CType으로 형변환을 한 후에 자식 메소드를 호출해주어야 한다.
마찬가지로 루프를 돌릴수 없다.
그러면 가상 메소드를 사용해보자.
부모 클래스에 가상메소드에서 똑같은 이름으로 사용하는 메소드를 부모 클래스에서 Overridable 함께 선언을 하고. 자식클래스의 메소드에는 Overrides를 지정하게되면, 가상 메소드를 호출하게 되면, 부모 클래스 변수에 할당된 개체의 형에 따라서 그 클래스의 메소드를 호출하게 된다.

확장메소드는 클래스의 멤버를 확장시켜 준다. 확장메소드 지정은 모듈에서 지정해야 한다.
다음과 같은 Imports System.Runtime.CompilerServices 구문이 필요하다.

<Extension()>
Public Sub DisplayString(ByVal obj As String) As String
   console.writeline(obj)
End Function

위 구문은 해당 프로젝트에서 String 클래스의 메소드에 DisplayString이라는 확장 메소드를 추가한다.
String 개체.DisplayString로 사용할수 있다.

확장 메서드(Visual Basic)
전처리기는 말 그대로 실제 실행 코드를 실행하기 전에 실행을 준비하는 과정에서 처리되는 부분을 말한다.
전처리기는 #문자로 시작하여 지정할수 있다.
상수 선언은 전처리기 내에서만 사용되는 상수를 지정한다.
#CONST 상수명 = 값
조건문은 전처리기 내에서 조건을 판단하기 이ㅜ해서이다.
#IF, #ELSE, #ELSEIF, #END IF
실행코드의 If와 다를게 없다.

다음은 위의 사용 예이다.
#CONST PCBIT=16
#IF PCBIT=16 THEN
     Private Value as Integer
#ELSE
     Private Value as Long
#END IF
위를 실행하면 Value는 Integer 형으로 선언된다.
그렇지만 #CONST PCBIT=16에서 지정한 상수 값이 다른 값이라면 Value는 Long형으로 선언된다.

#CONST PCBIT=16은 코드로 정의할수 있지만, IDE 환경에서 정의할수도 있다.
프로젝트 속성의 만들기 탭에서 조건부 컴파일 인수의 텍스트박스에 아래 이미지처럼 지정할 수 있다.

위 이미지는 #CONST PCBIT=16과 같은 뜻이다.

● 지정된 윈도우의 핸들의 DC를 얻는다.
● 반환은 ReleaseDC를 사용한다.
● 원형
HWND WINAPI GetDesktopWindow(void); 
선언 
GetWindowDC Lib "user32" (ByVal hwnd As Long) As Long
● 인수
hwnd ━ DC를 얻고 싶은 윈도우 핸들, Null(0)이면 전체 화면 DC를 반환한다.
● 반환
성공 ━ 핸들에서 얻은 DC
실패 ━ Null

'API > 선언' 카테고리의 다른 글

KillTimer 함수  (0) 2011.10.21
CopyMemory,MoveMemory,RtlMoveMemory 함수  (0) 2011.10.15
WM_ACTIVATE 윈도우 메세지  (0) 2011.10.13
ReleaseDC 함수  (0) 2011.10.11
GetDC 함수  (0) 2011.10.11
캐럿(Caret)이란 텍스트 박스(입력 상자)에서 입력 위치를 나타내주는 일잔적인 I자 모양을 캐럿이라고 한다.
비트맵을 로드 하여 캐럿을 생성하고, 텍스트 박스에 캐럿을 표시하는 형태이며
윈도우 활성,비활성을 알아보기 위해서 서브 클래싱을 사용했으면
WM_ACTIVATE 윈도우 메세지로, 윈두우 프로시저에서 윈도우 활성,비활성을 확인한다.

다음은 소스이다.
' 모듈 소스
Option Explicit

Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal MSG As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Public Const WA_INACTIVE = 0
Private Const WM_ACTIVATE = &H6

Public PreviosWindowProcedure As Long

Public Function WndProc(ByVal hWnd As Long, ByVal MSG As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    If MSG = WM_ACTIVATE And Not ((wParam & &HFFFF&) = WA_INACTIVE) Then
        Form1.TextShowCaret
    End If
    WndProc = CallWindowProc(PreviosWindowProcedure, hWnd, MSG, wParam, lParam)
End Function

'폼 소스
Option Explicit

Private Declare Function CreateCaret Lib "user32" (ByVal hWnd As Long, ByVal hBitmap As Long, ByVal nWidth As Long, ByVal nHeight As Long) As Long
Private Declare Function DestroyCaret Lib "user32" () As Long
Private Declare Function ShowCaret Lib "user32" (ByVal hWnd As Long) As Long
Private Declare Function LoadImage Lib "user32" Alias "LoadImageA" (ByVal hInst As Long, ByVal lpsz As String, ByVal un1 As Long, ByVal n1 As Long, ByVal n2 As Long, ByVal un2 As Long) As Long
Private Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long
Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Private Const GWL_WNDPROC = (-4)
Private Const IMAGE_BITMAP = 0
Private Const LR_LOADFROMFILE = &H10

Private BitmapID As Long ' 이미지 핸들
Private FilePath As String ' 파일 경로

Private Sub Form_Load()
    FilePath = App.Path & "\mypic.bmp"
    BitmapID = LoadImage(App.hInstance, FilePath, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE)
    PreviosWindowProcedure = SetWindowLong(Me.hWnd, GWL_WNDPROC, AddressOf WndProc)
End Sub

Private Sub Form_Unload(Cancel As Integer)
    SetWindowLong Me.hWnd, GWL_WNDPROC, PreviosWindowProcedure
    DestroyCaret
    DeleteObject BitmapID
    BitmapID = 0
End Sub

Private Sub txtCaret_Click()
    TextShowCaret
End Sub

Private Sub txtCaret_GotFocus()
    TextShowCaret
End Sub

Public Sub TextShowCaret()
    If BitmapID = 0 Then Exit Sub
    With txtCaret
        .SetFocus
        CreateCaret .hWnd, BitmapID, 0, 0
        ShowCaret .hWnd
    End With
End Sub

 

● 윈도우가 활성,비활성화 될 때 발생한다
● 원본
#define WM_ACTIVATE 0x0006
● 선언
WM_ACTIVATE= &H6
● wparam
하위 워드는 윈도우가 활성,비활성인지를 나타낸다.
윈도우가 최소화 상태인지를 나타낸다. 0이 아닌 값이면 최소화 상태
● lparam
윈도우 활성될때 이전의 활성 윈도우 핸들,윈도우가 비활성 될 때 다음에 활성되는 윈도우 핸들
● 상수
wparam 하위 워드 사용, 윈도우 활성,비활성 여부

상수 설명
WA_ACTIVE 1 활성
WA_CLICKACTIVE 2 마우스 클릭에 의한 활성
WA_INACTIVE 0 비활성

'API > 선언' 카테고리의 다른 글

KillTimer 함수  (0) 2011.10.21
CopyMemory,MoveMemory,RtlMoveMemory 함수  (0) 2011.10.15
GetWindowDC 함수  (0) 2011.10.13
ReleaseDC 함수  (0) 2011.10.11
GetDC 함수  (0) 2011.10.11


이 게시물에서는 하노이탑의 규칙성에 대해 이야기해 보려합니다.

게임규칙.
1. 한번에 하나만 이동.(모든 원판을 마지막 기둥으로.)
2. 작은원반 위로 큰 원반을 이동할 수 없다.
3. 최소 이동횟수로 이동. (최소이동횟수=2^원판수-1)
    원판이 3개일때 최소이동횟수는 2*2*2 -1 =7 회
4. 가장위의 원판만 이동가능.



최소이동 횟수:
원판 3 개 : 2*2*2-1 = 7 회
원판 4 개 : 2*2*2*2-1 = 15 회
원판 5 개 : 2*2*2*2*2-1 = 31 회
원판 6 개 : 2*2*2*2*2*2-1 = 63 회
원판 7 개 : 2*2*2*2*2*2*2 -1 = 127 회

이동하려는 원판의 수가 짝수와 홀수일때 맨위의 원판을 이동하는 기둥이 다르다는것과 이동의 목표가 맨아래의 원판을 이동가능하게 하기위한것이란 걸 염두에 두시면 쉽게 진행될 것입니다.

아래는 5개의 원판을 최소회수로 이동하는 방법(규칙) 을 플래시로 제작한 것입니다.
(목표기둥: 가장 오른쪽기둥)

[Flash] http://secstart.tistory.com/attachment/fk82.swf


 

이동법칙:
이동하려는 원판의 수가 홀수일때는 목표하는 막대로 보내고
이동하려는 원판의 수가 짝수일때는 목표하는 막대를 제외한 막대로 먼저 보낸다.


하노이의 탑 의 규칙성

첫번째. 원판이 둘일때를 생각해 봅니다. 가장위의 원판을 목표하는 기둥으로 보내면 가장아래원판을 이동할수 없지요. 그래서 맨위의 원판을 목표기둥 이외의 기둥으로 보냅니다. 그리곤 맨아래 원판을 목표기둥으로 보내고 빼두었던 맨위의 원판을 목표기둥으로 보내면됩니다.


두번째. 원판이 셋일때를 생각해 봅니다. 둘일때와 같이 맨위의 원판을 빈기둥으로 보내면 될까요? 이렇게 해서는 맨아래의 원판을 최소횟수로 빼낼수가 없습니다. 그래서 셋일때는 맨위의 원판을 목표한 기둥으로 보냅니다.그리고 가운데 원판을 빈 기둥으로, 맨아래 다시 맨위의 원판을 가운데 원판위에 놓습니다. 이제 맨아래 원판을 목표기둥으로 보냅니다. 두개의 원판이 남았죠?
이는 첫번째 경우와 같은 방법으로 목표기둥으로 보내면 됩니다.

이둘이 하노의 탑을 최소횟수로 이동하는 가장 큰 핵심알고리즘입니다. 원판이 많아져도 셋과 둘일때와 같은 방법, 곧 원판이 짝수일때와 홀수 일때로 나누어 생각하면 되지요.

원본 http://secstart.tistory.com/246

'기타 > 퍼온글' 카테고리의 다른 글

링크  (0) 2020.10.31

● 원형
int ReleaseDC(
  __in  HWND hWnd,
  __in  HDC hDC
)
● 지정된 윈도우의 DC를 반환,해제한다
GetWindowDC, GetDC로 얻은 DC
● 선언
ReleaseDC Lib "user32" (ByVal hwnd As Long, ByVal hDC As Long) As Long
● 인수
hwnd ━ 반환할 DC를 갖는 핸들
hDC ━ 반환할 DC
● 반환
성공 ━ 1이면 반환
실패 ━ 0이면 반환 실패


'API > 선언' 카테고리의 다른 글

KillTimer 함수  (0) 2011.10.21
CopyMemory,MoveMemory,RtlMoveMemory 함수  (0) 2011.10.15
GetWindowDC 함수  (0) 2011.10.13
WM_ACTIVATE 윈도우 메세지  (0) 2011.10.13
GetDC 함수  (0) 2011.10.11

● 원형
HDC GetDC(
  __in  HWND hWnd
)
● 지정된 윈도우 핸들에서 클라이언트 영역만 사용 가능한 DC(커먼 DC)를 얻는다.
● 반환은 ReleaseDC를 사용한다.
● 선언
GetDC Lib "user32" (ByVal hwnd As Long) As Long
● 인수
hwnd ━ DC를 얻고 싶은 핸들
● 반환
성공 ━ 핸들에서 얻은 DC의 핸들
실패 ━ Null

'API > 선언' 카테고리의 다른 글

KillTimer 함수  (0) 2011.10.21
CopyMemory,MoveMemory,RtlMoveMemory 함수  (0) 2011.10.15
GetWindowDC 함수  (0) 2011.10.13
WM_ACTIVATE 윈도우 메세지  (0) 2011.10.13
ReleaseDC 함수  (0) 2011.10.11
■ DC는 Device Context의 약자로 출력(화면 출력,프린터 출력 등등)에 필요한 모든 정보를 가지는 구조체이며, 윈도우 상의 모든 출력 함수는 이 DC를 참조하여 출력을 하게 되며, 이 DC를 지칭하는 고유한 번호가 HDC(Handle Device Context)이다. 이 HDC를 사용하여 특정한 DC를 지정한다.

DC에는 그리기에 필요한 여러 가지 정보가 저장되어 있으며, 출력 함수들은 DC의 정보를 참조하여 그리기를 하고, DC의 정보를 조작하여 그리는 방법을 변경한다. 운영체제는 프로그램들끼리 상호 영역을 침법하지 않고 최대한 효율적으로 그리기를 할 수 있도록 DC의 정보를 관리한다.

■ DC 구조체의 멤버
멤버 초기값
배경색상 제어판에서 지정한 윈도우의 배경색
배경모드 불투명(QPAQUE)
비트맵 선택되지 않은 상태
브러시 흰색 브러시,WHITE_BRUSH
브러시 원점 (0,0)
클리핑 영역 작업영역 전체
팔레트 DEFAULT_PALETTE
펜 위치(CP) (0,0)
장치 원점 작업영역의 좌상단
그리기 모드 R2_COPYPEN
폰트 SYSTEM_FONT
자간 0
맵핑 모드 MM_TEXT
BALCK_PEN
다각형 채우기 모드 ALTERNATE
스트레치 모드 BLACKONWHITE
덱스트 색상 제어판에서 설정한 텍스트 색상
뷰포트 확장 (1,1)
뷰포트 원점 (0,0)
윈도우 확장 (1,1)
윈도우 원점 (0,0)
DC는 그리기 관련 정보의 집합된 구조체로 멤버가 좀 많은 구조체일 뿐이다. 이 구조체에는 그리기에 필요한 각종 정보가 멤버로 포함되어 있다. 이 외에도 훨씬 더 많은 런타임 데이터들이 포함될 것이다.

운영체제는 프로그램이 DC를 요구할 때마다 DC에 적절한 초기값을 대입하여 그 핸들(HDC)을 넘겨준다. 프로그램은 넘겨받은 DC핸들로 그림을 그리며 DC 정보가 정확한 이상 그리기는 항상 정확하게 수행된다고 보장할 수 있다.

■ DC의 타입에는 4가지가 있다.
디스플레이 DC 화면 출력에 사용된다.
프린터 DC 프린터 출력에 사용된다.
메모리 DC 비트맵 출력에 사용된다.
정보 DC 정보 취득을 위해 사용된다
디스플레이 DC는 다시 5가지로, 클래스 DC, 커먼 DC, 프라이빗 DC, 윈도우 DC, 페어런트 DC로 나누어진다.

■ 클래스 DC(Class Device Contexts)
16비트 호완을 위해서 있는것으로, 클래스 DC를 사용할 일이 있으면 프라이빗 DC를 사용을 권하고 있다

■ 커먼 DC(Common Device Contexts)
작업영역에 그리기를 하는 가장 보편적인 DC이며 화면 출력을 위해 사용하는 DC이다. GetDC나 BeginPaint로 DC의 핸들을 발급받으며 사용한 후에는 ReleaseDC나 EndPaint로 해제한다.

■ 프라이비트 DC(Private Device Contexts)
하나의 윈도우가 독자적으로 사용하는 DC이다. 커먼 DC는 그리기를 할 때마다 매번 발급받아야 하는데 비해 프라이비트 DC는 윈도우가 생성될 때 한번만 만들어지며 윈도우가 실행되는 동안 계속 존재한다. 그래서 프라이비트 DC에 한번 설정해 놓은 속성은 일부러 바꾸지 않는 한 계속 유효하며 그리기를 할 때마다 DC를 준비하지 않아도 되므로 그만큼 빠르게 그리기를 할 수 있다. 윈도우에서 이 DC를 사용기 위해서는 윈도우 클래스의 스타일에 CS_OWNDC 스타일을 지정해야한 다. 이런 스타일이 지정된 윈도우 클래스부터 윈도우가 만들어질 때마다 운영체제는 프라이비트 DC를 생성한다. 이렇게 생선된 DC의 핸들은 프로그램 전체를 통틀어 한번만(WM_CREATE 등에서) 읽으며 이 핸들로 모든 그리기를 할 수 있다. 윈도우 실행 주기 동안 계속 유지되는 DC이므로 사용 후에 해제할 필요도 없고 해제해서도 안된다. 윈도우가 파괴될 때 시스템이 DC를 파괴한다.

■ 윈도우 DC(Window Device Contexts)
윈도우 DC는 커먼 DC와 사용방법이 비슷하다. 차이점이라면 커먼 DC는 원점이 작업영역의 좌상단이지만 윈도우 DC는 윈도우의 좌상단이 원점이라는 점과 클리핑 영역이 작업영역에만 국한되는 것이 아니라 전체 윈도우라는 점이다. 그래서 윈도우 DC를 사용하면 작업영역뿐아니라 타이틀 바나 경계선에까지도 마음대로 출력할 수 있다. 윈도우 DC를 얻을 때는 GetWindowDC나 GetDCEx를 사용하고, 사용한 후에는 ReleaseDC로 해제한다.

■ 페어런트 DC(Parent Device Contexts)
클리핑 영역을 계산하는 시간을 최소화하기 위해 사용한다. 주로 버튼이나 에디트 등의 차일드 컨트롤에서 그리기 속도를 최대한 빠르게 하기 위해 사용되며 최상위 윈도우나 팝업 윈도우는 이 DC를 사용 할수 없다. 페어런트 DC를 사용하려면 윈도우 클래스의 스타일에 CS_PARENTDC 스타일을 지정한다. 윈도우는 페어런트 DC가 발급될 때 부모 윈도우가 사용하던 DC를 캐시에서 찾아 이미 계산되어 있는 클리핑 영역을 사용함으로써 최대한 시간을 아낀다.
이전 게시물에서 시이얼 포트 에물레이터 하는 툴 Virtual Serial Port Emulator을 소개했다.
http://infototal.tistory.com/admin/entry/edit/74?returnURL=/entry/virtualserialport 게시물에 가면 내용을 볼수 있다.

실전으로 VSPE(Virtual Serial Port Emulator)을 사용해서 한 PC에서 시리얼 포트로 입출력 하는 결과를 확인해보자. 이것을 응용하여 시리얼 포트 프로그램 작성시 한PC에서 테스트 하면 프로그램을 진행할 수 있을것이다.

준비할 툴은 Virtual Serial Port Emulator과 2개의 하이터 터미날, 메모장이 필요하다. 메모장 말고 다른 것으로 상관없다. 단지 텍스트 복사하세 클립보드에 저장되도록 하는 기능을 할 것이다. 이런 기능을 할 수 있는 툴이면 된다.

먼저 VSPE를 시작하고, 가상의 시리얼 포트를 만드는데 Pair로 만들어 한쪽 포트 입력을 다른쪽 포트 출력이 될수 있도록 해보자.

도구 모음에서 아래 이미지와 같은 버튼을 클릭한다.

아래 이미지와 같이 Specify device type라는 창이 뜨게 된다.

이 창에서 에뮬레이트 할 가상 시리얼 포트 타입을 지정할수 있다. 여기서는 시리얼 포트의 한쪽 입력을 한쪽 출력으로 해야 하기 때문에 두 포트를 연결하는 Pair를 선택하고,

다음 버튼을 클릭한다. 그러면 아래 이미지와 같은 Specify device characteristics 창이 뜨며, 서로 연결될 생성할 두개의 가상 포트에 할당된 포트 번호가 표시되다.

마침 버튼을 누르게 되면 두개의 가상 포트가 생성되며, 메인 창에 아래 이미지 와 같이 두 포트가 연결된 것으로 표시된다.

지금은 아직 가상 포트를 에뮬레이트 하는 상태는 아닌다. 도구 모음의 아래 이지미와 같은 Start emulation 버튼을 클릭하면 해당 가상 포트를 에뮬레이트 하게 된다.

버튼을 누르게 되면 Status 상태가 Ready 상태가 된다.


다음으로는 두 개의 하이퍼 터미날 시작해야 한다. 하이퍼 터미날은 시작-모든 프로그램-보조 프로그램-통신-하이퍼터미날을 선택해서 시작 할수 있다. 연결에서 연결에 사용할 모뎀으로 한쪽은 COM3으로 한쪽은 COM4로 지정한다. 즉 위 VSPE에서 Pair로 지정한 가상 시리얼 포트를 지정하면 된다.

메모장이나 기타 툴을 사용해서 클립보드에 텍스트를 복사 한다. 간단히 Ctrl+C를 누르는 것 만으로 클립보드에 복사할수 있다.
한쪽 하이퍼 터미알에서 메뉴의 편집에 호스트에 붙여넣기를 선택하면 다른쪽 하이퍼 터미날에 나타난다.

이미지 처럼 오른쪽 메모장에서 테스트입니다 문구를 클립보드에 복사하고(Ctrl+V), 왼쪽 하이퍼 터이말에서 편집에 호스트에 붙여넣기를 했더니 중간의 하이퍼 터미날에 표시된 이미지이다.

이 방법을 사용해서 시리얼 포트 프로그램을 작성할때 테스트 데이타를 입력,출력할 수 있다. 굳이 물리적으로 접속하지 않은 상태더라도 테스트 작업할수 있다.

'VB6' 카테고리의 다른 글

클래스 인터페이스 구현,Implements  (0) 2011.10.15
전처리기  (0) 2011.10.14
WMI를 사용한 프로세스 강제 종료  (0) 2011.10.07
리스뷰에 프로그래스 바 처럼 진행율 표시  (0) 2011.10.04
시리얼 포트 에물레이터  (0) 2011.10.02
API(Application Programming Interface)는 현재 프로그램 외부의 프로시저를 말한다.
이 프로시저를 VB6에서 호출하기 위해서는 다음과 같은 규칙이 필요하다.

우선 이런 현재 프로그램에서 어떤 외부 프로시저를 사용할지를 지정해 주어야 한다. 이것을 선언이라며, 각 모듈의 선두에 선언한다.
선언 형식은 다음과 같다.
Pricate Declare Function FindExecutable Lib "shell32.dll" Alias "FindExecutableA" (ByVal lpFile As String, ByVal lpDirectory As String, ByVal lpResult As String) As Long
호출은 일반 프로시저를 호출하는 식으로 하면 된다.

선언에서 선두의 Private의 선언한 프로시저를 적용하는 범위를 지정한다. Private이면 선언한 프로시저는 API가 선언된 모듈에서만 호출 가능하고, Public로 선언하면 API가 선언한 모듈을 포함하는 프로그램 내에서 어디서나 호출 가능하다.
Declare는 API 선언 이라는 것을 알릴 뿐이다.
Function는 API가 반환값을 갖는 프로시저인지(Function 지정), 반환값을 갖지 않는 프로시저인지(Sub 지정)를 나타낸다. 반환값이 없거나, 있다고 해도 사용하지 않는다면 Sub로 지정하면 된다.
FindExecutable는 API를 VB6에서 어떤 이름으로 호출할것인가를 나타내고, 또는 Alias를 지정하지 않은 경우 API의 외부 프로시저명이 어떤것으로 돼어 있는지를 나타낸다. DEPENDS.EXE를 사용하면 지정된 파일에 어떤 프로시저가 포함되어 있는지를 알수 있다. 여기서는 선언된 API를 VB6에서 호출할때 FindExecutabled라는 이름으로 호출하여 사용한다.
Lib "shell32.dll"는 선언한 API 즉 외부 프로시저가가 어떤 파일에 포함되었는지를 나타낸다.
Alias "FindExecutableA"는 vb6에서 호출에 사용할 이름과, 지정된 파일에 포함된 외부 프로시저명이 다를경우, 지정된 파일에 외부 프로저명을 지정한다.
다음은 vb6에서 프로시저 사용시 인수와 반환값 자료형 적는 부분은 같다.

한가지 주의할것은 vb6에서 인수로 반환값중 String을 사용하게 되는 경우 vb6에서 호출시에는 String의 값을 유니코드로 간주하고 ANSI코드로 변환하고 API를 호출하고, 반환시에는 거꾸로 String값을 ANSI코드로 간주하고 유니코드로 자동 변환한다. 이러한 자동 변환을 쓰지 않기 위해선 Byte 배열을 사용한다.












시리얼 포트는 직렬 통신을 하기 위한 포트를 말한다. 포트 번호명은 COM번호 형식으로 되어 있다.
레지스트리  HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM
에는 시스템에서 사용할 수 있는 시리얼 포트 목록이 저장되어 있다.

목록을 보면 가상 시리얼 포트도 포함되어 있다.
실제 존재하는 시리얼 포트 목록만 얻고 싶다면 WMI의 Win32_SerialPort 클래스를 사용하면 실존하는 시리얼 포트만 얻을 수 있다.

RegEnumValue를 사용하여 레지스트리에 시리얼 포트 저장된 키의 값을 읽어 시스템에 설정된 시리얼 포트를 나열한다.

위 이미지는 소스의 결과이다.
RegEnumValue는 오픈된 키에 값명과 값들을 인덱스 번호 0부터 시작하여, 지정된 항목의 값명과 값을 읽어온다.

오픈된 레지스트리 키에서 지정된 번호에 해당하는 값명과 값을 읽는다. 0부터 순차적으로 호출하여 ERROR_NO_MORE_ITEMS이 발생될까지 하면 해당 키의 전체 값명,값을 얻을 수 있다.

● 선언

Function RegEnumValue Lib "advapi32.dll" Alias "RegEnumValueA" (ByVal hKey As Long, ByVal dwIndex As Long, ByVal lpValueName As String, lpcbValueName As Long, ByVal lpReserved As Long, lpType As Long, lpData As Any, lpcbData As Long) As Long

● 인수

hKey ━ 오픈된 레지스트리키 핸들이나,정의된 레지스트리 특정키 상수
dwIndex ━ 읽을 키의 인덱스 번호 0이 첫번째
lpValueName ━ 키 이름을 저장할 버퍼
lpcbValueName ━ lpValueName 버퍼의 크기
lpReserved ━ 0
lpType ━ 키의 타입 저장될 변수
lpData ━ 키의 값을 받을 버퍼
lpcbData ━ lpData 버퍼의 크기

● 반환
성공 ━ ERROR_SUCCESS
실패 ━ 에러 코드

다음은 소스이다.
Option Explicit

Private Declare Function RegOpenKey Lib "advapi32.dll" Alias "RegOpenKeyA" (ByVal hKey As Long, ByVal lpSubKey As String, phkResult As Long) As Long
Private Declare Function RegCloseKey Lib "advapi32.dll" (ByVal hKey As Long) As Long
Private Declare Function RegEnumValue Lib "advapi32.dll" Alias "RegEnumValueA" (ByVal hKey As Long, ByVal dwIndex As Long, ByVal lpValueName As String, lpcbValueName As Long, ByVal lpReserved As Long, lpType As Long, lpData As Any, lpcbData As Long) As Long
Private Const HKEY_LOCAL_MACHINE = &H80000002
Private Const ERROR_NO_MORE_ITEMS = 259
Private Const BUFFERSIZE = 255

Private Sub Form_Load()
    Dim OpenRegHwnd As Long ' 오픈된 레지스트리 키 핸들
    Dim ValueName As String ' 값명 버퍼
    Dim ValueNameSize As Long ' 값명 버퍼 사이즈, 및 버퍼에 저장된 값명 길이
    Dim Value As String ' 값 버퍼
    Dim ValueSize As Long ' 값 버퍼 사이즈, 및 버퍼에 저장된 값 길이
    Dim IndexCount As Long ' 값 인덱스 번호 카운터
   
    RegOpenKey HKEY_LOCAL_MACHINE, "HARDWARE\DEVICEMAP\SERIALCOMM", OpenRegHwnd ' 레지스트리 키를 오픈한다
    ValueName = String(BUFFERSIZE, " ")
    Value = String(BUFFERSIZE, " ")
    IndexCount = 0
    ValueNameSize = BUFFERSIZE
    ValueSize = BUFFERSIZE
    While Not ERROR_NO_MORE_ITEMS = RegEnumValue(OpenRegHwnd, IndexCount, ValueName, ValueNameSize, 0&, ByVal 0&, ByVal Value, ValueSize)
        List1.AddItem Left(ValueName, ValueNameSize)
        List2.AddItem Left(Value, ValueSize)
        IndexCount = IndexCount + 1
        ValueNameSize = BUFFERSIZE
        ValueSize = BUFFERSIZE
    Wend
    RegCloseKey OpenRegHwnd ' 오픈된 레지스트리 키를 닫는다.
End Sub

+ Recent posts