OS 윈도우의 대부분(버튼,입력박스,윈도우창 등)은 윈도우라고 하고 핸들을 갖으며

그 윈도우가 여러 종류의 메세지(윈도우 메세지)를 받고 각 메세지에 따른 처리를 한다.

그 윈도우 핸들을 찾는 도구는 spy++이라는 도구가 있으며

사용법은 도움말이, 기타 검색을 하면 많은 정보가 나온다.

 

여기서는 윈도우 핸들을 찾기 위해서

findwindow나 findwindowex API를 사용 계단식으로 점차 내려가는것이 아니라.

코드를 작성하여 제일 상단의 윈도우 핸들을 주고, 그 하부의 윈도우를 검색하여

조건에 일치하는 핸들을 반환해주는 소스를 작성할가 한다.

 

spy++를 사용 IE 브라우저의 윈도우 핸들을 보았다.

(사용자 OS마다 구조가 틀릴수 있습니다)

SPY++로 본 계층 구조로 표시된 윈도우 핸들

위 그림처럼 핸들이 계단식으로 쭉 나와있다.

상위의 핸들 006B0712(Google 드라이브 - Internet Explorer)에서

하위의 00B09A2(Internet Explorer_server) 까지의 핸드를 찾기 위해서는

5회의 findwindow와 findwindowex API를 사용하여 찾을수 있다.

 

재귀함수를 사용 상위의 핸들과, 찾을 조건을 주어 하위에 있는 핸들중 일치하는 첫번째 윈도우를  반환하는 함수이다.

핸들 찾는 재귀함수 코드

인수로 상위 위도우 핸들, 찾을 윈도우 클래스명, 찾을 윈도우 타이틀 을 주면 된다.

 

다음 이미지는 디버그 창에서 위 코드 함수를 호출한 결과이다.

결과

ie.hwnd는 브라우저 핸들이고, 위 SPY++그림의 상위 핸들(006B0712)과 같다.

결과는 찾고자 하는 핸들((Internet Explorer_server) 00B09A2가 나왔다.

vb6에서 실행파일을 도스창(명령줄), 또는 shell 함수로 실행시 사용자가

적었던 실행파일명과 인수들중 인수들을 해당 프로그램에서 알수 있다.

 

명령줄로 다음과 실행했다고 하자.

명령줄에서 인수와 같이 프로그램 실행

해당 프로그램에서

command 함수나 command$ 함수를 사용하면 주어진 인수들을 알수 있다.

*Visual Basic For Application(VBA)-Interaction 모듈에 들어있는 함수이다. 개체찾아보기에서 찾아볼수 있다.

*command와 command$의 차이는 리턴 타입이 다르다.

*command는 variant형으로 리턴하고, commad$는 String 형으로 리턴한다.

위 이미지처럼 인수를 2개를 썻는대 구분해서 리턴해주는 것이 아니라

하나의 문자열로 통으로 리턴해주기 때문에 2개 이상의 인수가 필요할때는

사용자가 이것을 구분해 주어야 한다.

 

split(command$," ")을 사용하여 인수를 분리한다.

인수를 분리를 하긴 했는대, ""(따옴표)로 둘러싼 인수는 하나로 봐서 분리하면 안돼는대

하나로 해주어야 하는대 추가적인 처리를 해주어야 할거 같다.

이런식으로

 

split 문자를 검사하여 따옴표기 있는지 없는지를 인수를 연결할건지 말건지를 판단하는 루프가 있어야 한다.

다음은 소스이다.

 

32bit 환경에서(xp 이상 OS들)는 정수 자료형을 integer가 아닌 long으로 선언해서 사용할것을 권한다.

lenb를 사용하면 각 자료형의 크기를 알수 있는대

integer 은 2바이트 즉 16비트

long은 4바이트 즉 32비트

 

 

오래된 툴이다 보니 요즘 OS에서는

잘 설치가 안되거나, 설치가되도 제대로 돌아가지 않는

경우가 많다.

 

그래도 안정적인 설치 방법은

ms office 2003 설치후에 vs6를 설치하니

vb나 vc가 그래도 안정적으로 돌아간다.

 

설치후에 서비스팩도 설치하고 호환성 설정하고 하면

그래도 안정적으로 돌아간다.

http://www.codeproject.com/Articles/26822/Read-Text-File-txt-csv-log-tab-fixed-length

첫번째 방법

debug 개체 사용

debug 개체는 다자인 타임에는 실행되지만

컴파일할때 이 이 제외된 상태에서 컴파일이 되기 때문에 이를 이용한다.

 

on error resume next

debug.print 1/0 ' 일부러 에러 발생시킨다

if err.number > 0 then msgbox "디자인 타임" else msgbox "런타임"on

on error goo 0

 

두번째 방법

API FindWindow를 사용

IDE 환경에서는 VB창이 떠있는것을 사용하여

If FindWindow("클래스명IDEOwner", vbNullString) > 0 Then msgbox "디자인타암" Else msgbox "런타임"

 

세번째 방법

API GetModuleHandle 사용

현재 프로세스에서 로드된 모듈을 확인한다.

Dim ModuleHandle As String Dim EnvFileName As String Dim EnvVal As Variant Dim ReturnVal As Long Dim i As Long EnvVal = _ Array("vb.exe", _ "vb32.exe", _ "vb5.exe", _ "vb6.exe") For i = LBound(EnvVal) To UBound(EnvVal) ModuleHandle = EnvVal(i) ReturnVal = GetModuleHandle(ModuleHandle) If ReturnVal <> 0 Then EnvFileName = ModuleHandle TestEnvironment = True Exit For End If Next if TestEnvironment then msgbox "디자인타임" else msgbox "런타임"

windows 7에서 vb6의 IDE(통합개발) 환경에서 dateadd,datediff 에러가 발생된다.

그러나 런타임 환경에서는 제대로 실행된다.

런타임에서도 제대로 실행되지 않으면

실행 파일의 속성(파일에서 오른쪽 버튼 누른 경우 팝업되는 메뉴)에서

호완성을 xp로 관리자 권한으로 실행하면 된다

 

 아마 IDE 환경에서 vb6.dll을 제대로 로딩하지 못해서 그렇치 않을가 한다.

아니면 vba6.dll을 대체할 windows7에서의 DLL을 사용하지 않아서 그럴지도 모른다.

IDE의 상태와, 런타임시의 로드한 모듈을 비교해보면 서로 다른다.

실행파일에서는 vba6.dll이 로드 되지 않고, windows 7에서 사용한 모듈이

대신 로드되어 있다. 그러나 IDE에서는 vb6.dll이 로드외어 있다.

이것이 windows7의 실행과 충돌이 되는 것이 아닐가한다.

 

IDE 환경에서도 dateadd,datediff를 사용하려면

따로 함수를 작성하는 방법이 있겠고

또는 직접 연산하는 방법을 사용하는 방법으로 사용해야 한다.

만약

dateadd("n",30,now) 라면

now+cdate("0:30:00") 이런식으로 연산하는 방법이 있다.

웹브라우저나,익스플로어 관련 컨트롤이나 참조하고나, 포함하는 프로젝트를 로드하는 경우

ieframe.dll\1 에러가 발생되면

실행에서 레지스트리편집기(regedit)에서

ieframe.dll\1을 찾아 ieframe.dll로 수정한다.

어떤 모듈(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

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 생성할수 있으면 다시 이전의 호환성으로 선택하면 된다.
전처리기는 말 그대로 실제 실행 코드를 실행하기 전에 실행을 준비하는 과정에서 처리되는 부분을 말한다.
전처리기는 #문자로 시작하여 지정할수 있다.
상수 선언은 전처리기 내에서만 사용되는 상수를 지정한다.
#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과 같은 뜻이다.
이전 게시물에서 시이얼 포트 에물레이터 하는 툴 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를 사용할 수 없다. 따라서 스크립트 언어에서 API와 같은 기능에 접근하기 위한 방법으로 WMI를 재공한다.

VB6에서 WMI를 사용하기 위해서는 Microsoft WMI Scripting V1.2 Library 참조(프로젝트 메뉴의 참조)가 필요하다.

다음 소스는 종료 하고자 하는 프로세스에서 포함하는 윈도우를 클릭하는 경우, 윈도우에 해당하는 프로세스 ID를 얻고, WMI를 사용하여 프로세스를 종료하는 방법이다.

훅 프로시저에서 WMI를 사용할 수 없으므로(이유는 모름) 타이머를 사용하여 WMI를 사용 프로세스를 종료시키는 프로시저를 호출하게 했다.

다음은 소스이다.
'폼 모듈 소스
' WMI를 사용한 프로세스 강제 종료
Option Explicit ' 모든 변수는 선언된 뒤에 사용할 수 있다.

Private Declare Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" (ByVal idHook As Long, ByVal lpfn As Long, ByVal hmod As Long, ByVal dwThreadId As Long) As Long ' 훅체인에 훅프로시저를 선두에 끼워넣는다, 성공하면 훅프로시저의 핸들을 복귀한다.
Private Declare Function UnhookWindowsHookEx Lib "user32" (ByVal hHook As Long) As Long ' 훅체인에서 훅 핸들이 나타내는 훅 프로시저를 제거한다.
Private Const WH_MOUSE_LL = 14

Private hhkLowLevelMouse As Long  ' 훅 설치가 완료되는경우, 그 훅을 나타내는 핸들

Private Sub Form_Load()
    GetWindowThreadProcessId Me.hWnd, MyPid
    hhkLowLevelMouse = SetWindowsHookEx(WH_MOUSE_LL, AddressOf LowLevelMouseProc, App.hInstance, 0)
End Sub

Private Sub Form_Unload(Cancel As Integer)
    If hhkLowLevelMouse = 0 Then Exit Sub
    UnhookWindowsHookEx hhkLowLevelMouse ' 훅을 체인에서 훅 제거한다.
    hhkLowLevelMouse = 0
End Sub

' 일반 모듈 소스
' Microsoft WMI Scripting V1.2 Library 참조
' WMI 사용을 위해서는 Microsoft WMI Scripting V1.2 Library 참조가 필요하다.
' 훅 프로시저에서 WMI가 실행이 않된다(이유 모름)
Option Explicit ' 모든 변수는 선언된 뒤에 사용할 수 있다.

Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long) ' 메모리 내용을 복사한다.
Private Declare Function CallNextHookEx Lib "user32" (ByVal hHook As Long, ByVal nCode As Long, ByVal wParam As Long, lParam As Any) As Long ' 훅체인에서 다음 훅프로시저를 호출한다.
Private Declare Function WindowFromPoint Lib "user32" (ByVal xPoint As Long, ByVal yPoint As Long) As Long
Private Declare Function SetTimer Lib "user32" (ByVal hWnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long
Private Declare Function KillTimer Lib "user32" (ByVal hWnd As Long, ByVal nIDEvent As Long) As Long
Public Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hWnd As Long, lpdwProcessId As Long) As Long
Private Const HC_ACTION = 0
Private Const WM_LBUTTONDOWN = &H201

Private Type POINTAPI
    X As Long
    Y As Long
End Type

Private Type MSLLHOOKSTRUCT
    pt          As POINTAPI
    mouseData   As Long
    flags       As Long
    time        As Long
    dwExtraInfo As Long
End Type

Public MyPid As Long ' 현재 프로세스의 PID
Private KillPid As Long ' 삭제할 프로세스 PID

Public Function LowLevelMouseProc(ByVal nCode As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    Dim p As MSLLHOOKSTRUCT
    Dim Windowhwnd As Long ' 마우스 위치의 윈도우 핸들
    Dim Pid As Long ' 해당 윈도우를 갖는 프로세스 ID

    If (nCode = HC_ACTION) And wParam = WM_LBUTTONDOWN Then
        CopyMemory p, ByVal lParam, Len(p)
        Windowhwnd = WindowFromPoint(p.pt.X, p.pt.Y)
        GetWindowThreadProcessId Windowhwnd, Pid
        If Not Pid = MyPid Then         'KillByPidUseWMI Pid ' 현재 프로세스 인경우는 제외
            KillPid = Pid
            SetTimer 0&, &H5000, 100, AddressOf KillByPidUseWMI

        End If
    End If
    LowLevelMouseProc = CallNextHookEx(0, nCode, wParam, ByVal lParam)
End Function

Public Sub KillByPidUseWMI(ByVal hWnd As Long, ByVal uMsg As Long, ByVal idEvent As Long, ByVal dwTime As Long)  ' WMI를 사용한 프로세스 ID에 해당하는 프로세스 강제 종료
    Dim oWMI  As SWbemLocator
    Dim oItms As SWbemServices
    Dim oresu As SWbemObjectSet
    Dim ore As SWbemObject

    KillTimer hWnd, idEvent ' 타이머를 제거한다.
   
    Set oWMI = New SWbemLocator
    Set oItms = oWMI.ConnectServer(Environ("ComputerName"), "root\CIMV2")
    Set oresu = oItms.ExecQuery("SELECT * FROM Win32_Process WHERE Handle=" & KillPid)
   
    For Each ore In oresu
        ore.Terminate
    Next
    Set oresu = Nothing
    Set ore = Nothing
    Set oWMI = Nothing
    Set oItms = Nothing
End Sub

픽처박스와 프로그래스 바를 하나 생성하고, 픽처박스에 프로그래스바를 넣고, 픽처박스에 프로그래바를 포함한 내용을 다시 그리다음, 픽처박스의 image를 이미지리스트에 추가하고 이것을 리스트뷰와 연결해 주면 된다.

다음은 초기 이미지이다.


진행 프로그래스바 표시 버튼을 눌르면 리스트뷰에 진행율 프로그래스바가 표시된다.
프로그래스바와, 픽처박스는 감춰줘있다.


다음은 소스이다.

' 리스트 뷰에 프로그래스 표시
Option Explicit

Private Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long ' 메세지를 보낸다.

Private Const WM_PAINT = &HF
Private Const WM_PRINT = &H317
Private Const PRF_CHILDREN = &H10&
Private Const PRF_CLIENT = &H4&

Private Sub Command1_Click()
    Dim NewItem As ListItem

    ListView1.ListItems.Clear
    ImageList1.ListImages.Clear
    Set NewItem = ListView1.ListItems.Add(, vbNullString)
    NewItem.SubItems(1) = "테스트"
    NewItem.SubItems(2) = vbNullString
    ImageList1.ListImages.Add , , Picture1.Image
    NewItem.ListSubItems(2).ReportIcon = ImageList1.ListImages.Count
    Timer1.Enabled = True
End Sub

Private Sub Form_Load()
    With ListView1
        .ColumnHeaders.Add 1, , vbNullString, 0, 0
        .ColumnHeaders.Add 2, , "테스트", 120, 0
        .ColumnHeaders.Add 3, , "진행률", 250, 0
    End With
    With Picture1
        Picture1.Line (.ScaleTop, .ScaleLeft)-(.ScaleWidth - 1, .ScaleHeight - 1), vbBlack, B
        ProgressBar1.Move .ScaleTop, .ScaleLeft, .ScaleWidth, .Height
        ProgressBar1.Max = .ScaleWidth
    End With
End Sub

Private Sub Timer1_Timer()
    Static CountNumber As Long
   
    ProgressBar1.Value = (ProgressBar1.Max - ProgressBar1.Min) * (CountNumber * 0.01)
    SendMessage Picture1.hwnd, WM_PAINT, Picture1.hDC, 0 ' 소스 픽처박스의 클라이언트 영역을 픽처박스에 그린다, 이미지는 윈도우가 아니라 클라이언트 영역의 일부를 사용하므로, 이미지 컨트롤의 이미지가 그려진다. 화면과,Image 속성에도 그려진다.
    SendMessage Picture1.hwnd, WM_PRINT, Picture1.hDC, PRF_CHILDREN Or PRF_CLIENT ' 이번에 픽처박스 클라이언트 위의 컨트롤들을 메모리(Image 속성)에 그린다.
    With Picture1
        Picture1.Line (.ScaleTop, .ScaleLeft)-(.ScaleWidth - 1, .ScaleHeight - 1), vbBlack, B
    End With
    ImageList1.ListImages.Add , , Picture1.Image
    ListView1.ListItems(1).ListSubItems(2).ReportIcon = ImageList1.ListImages.Count
    ListView1.ListItems(1).ListSubItems(2).Text = CountNumber & " %"
    If CountNumber >= 100 Then
        Timer1.Enabled = False
    Else
        CountNumber = CountNumber + 5
        If CountNumber > 100 Then CountNumber = 100
    End If
End Sub

툴 이름은 Virtual Serial Port Emulator이다.

시리얼 포트를 에물레이터 해주는 툴이다.
가상의 시리얼 포트를 만들거나, 두 포트를 연결해주는 시리얼 포트를 만든다.
시리얼 포트 프로그램을 작성시에 사용하면 유용할 듯 한다.

다음은 두개의 시리얼 포트를 연결한 가상의 시리얼 포트를 생성한 이미지이다.


가상의 2개의 시리얼 포트 생성하고 두 포트를 연결한 것이다.
즉 한쪽의 가상의 시리얼 포트에 입력은 다른 가상의 사리얼 포트의 출력으로 나오게 된다.


http://www.eterlogic.com/Downloads.html 가면 다운로드 받을수 있다.

replace(format(출력할 수치나 문자,"자릿수 만큼 @")," ",공백 대신 채울 문자)

replace(format(hex(15),"@@")," ",0)
결과는 0f
  • VB6에서 문자는 내부적으로는 유니코드로 처리된다.
    유니코드로 저장될때는 영문이던, 한글이던 어떤 문자가 저장될 때는 2바이트가 필요하다.
    유니코드가 메모리에 저장될때에는 바이트 순서가 바뀌어서 저장된다.(8086 계열)
    "가"라는 문자가 저장된다고 할때. "가"에 문자의 유니코드는 &HAC00이다. 이것이 메모리에 저장될때는
    첫번째 바이트에 &h00이 두번째 바이트에는 &hAC가 저장된다.

    기본 내장함수 asc와 ascb와 ascw의 차이점을 보면
    -asc에서 인수에 전달한 값은 유니코드로 간주하며 주어진 인수의 2바이트를 ANSI 문자로 바꾸어 그 코드를 반환한다.
    즉, asc("가")를 하게 되면 "가"에 대한 유니코드 값이 반환 되는 것이 아니라 "가"에 대한 ANSI 코드가 반환단다.
  • ascb는 주어진 인수가 유니코드인지 ANSI 코드 인지 관계없이 메모리에 저장된 첫번째 바이트 값을 반환한다.
    즉 ascb("가")를 하개 되면 &h00이 반환된다.
  • ascw는 주어진 인수가 유니코드라고 간주하고 인수의 2바이트 값을 얻은후에 서로 위치를 바꾼후의 값을 반환한다.
    ascw("가")를 하게 되면 &HAC00이 반환된다.
  • 한가지 더, midb도 마찬가지로 현재 메모리에 저장된 순으로 값을 가져온다.

 

 

 

 

 

 

엑셀을 참조하여 사용할경우, 값을 지정해야 할 곳에 개체를 지정하면 발생되면
예로
하나의 셀의 값으로 개체를 지정하였다면 이 에러가 발생한다.
a가 개체라고 할때
cells(1,1)=a
하면 98 에러가 발생한다.


사용자 정의 컨트롤에 AsyncRead 메소드는 지정된 URL에서 다운로드 한다(이미지나, 파일)
다운로드한 데이타를 이미지 또는 이진 데이타로 취급할지를 나타내다.

다운로드 시작시는 사용자 정의 컨트롤에 AsyncRead와 URL, 타입을 지정하면 된다.

다운로드 완료시는 사용자 정의 컨트롤에 AsyncReadComplete 이벤트가 발생하며
이벤트 발생할때 AsyncProp인수가 전달되며
AsyncProp의 Value 값을 참조하면 다운로드한 값을 얻을수 있다.

AsyncReadProgress 이벤트는 다운로드 중에 데이타가 다운로드 될때마다 발생된다.
이벤트 발생할때 AsyncProp인수가 전달되며
AsyncProp의 BytesMax를 참조하면 다운로드할 데이타의 전체 크기
AsyncProp의 BytesRead를 참조하면 현재까지 다운로드한 데이타의 크기를 얻을 수 있다.

우선 프로젝트에 사용자 정의 컨트롤을 하나 추가한다.


다음 이미지는 소스의 초기 이미지이다.


다음 이미지는 다운로드 진행중인 이미지이다.


진행률 표시는 픽처박스와 2개의 레이블을 사용해서 표시했다.

다음은 소스이다.
폼의 소스이다.
'폼에 사용자 정의 컨트롤과,픽처박스,커맨드 버튼을 올린다
Option Explicit

Private Sub cmdStart_Click() ' 다운로드 시작
    UserControl11.Read "http://www.shareware.co.kr/action/getFile.asp?id=602a919e&sh=T"
End Sub

Private Sub Form_Load()
    With labProgress
        .BorderStyle = vbBSNone
        .Top = -10
        .Left = 0
        .Visible = False
        .BackColor = vbBlack
    End With
    With labProgressValue
        .BorderStyle = vbBSNone
        .Width = picProgress.ScaleWidth
        .Left = 0
        .Top = (picProgress.ScaleHeight - .Height) / 2
        .Alignment = vbCenter
        .ForeColor = vbWhite
        .BackStyle = vbTransparent
    End With
End Sub

Private Sub UserControl11_DownloadComplete(Data() As Byte) ' 다운로드 완료시 발생
'    Dim fd As Integer
'    fd = FreeFile ' 데이타를 파일로 저장
'    Open "a.exe" For Binary As #fd
'    Put #fd, 1, Data
'    Close #fd
End Sub

Private Sub UserControl11_DownLoadProgress(ByVal MaxByte As Long, ByVal ProgressByte As Long) ' 다운로드 진행 중에 발생
    If MaxByte = 0 Then Exit Sub
    labProgress.Visible = True
    labProgress.Width = (picProgress.ScaleWidth * ProgressByte) / MaxByte
    labProgressValue.Caption = ProgressByte & " / " & MaxByte
End Sub

사용자 정의 컨트롤 소스이다.
' 사용자 정의 컨트롤
Option Explicit

Event DownloadComplete(Data() As Byte)
Event DownLoadProgress(ByVal MaxByte As Long, ByVal ProgressByte As Long)

Private Sub UserControl_AsyncReadComplete(AsyncProp As AsyncProperty)
    Dim Data() As Byte
   
    Data = AsyncProp.Value
    RaiseEvent DownloadComplete(Data)
End Sub

Public Sub Read(ByVal URL As String) ' 다운로드 시작 메소드
    UserControl.AsyncRead URL, AsyncTypeConstants.vbAsyncTypeByteArray ' 다운로드 시작
End Sub

Private Sub UserControl_AsyncReadProgress(AsyncProp As AsyncProperty) ' 다운로드 진행중
    RaiseEvent DownLoadProgress(AsyncProp.BytesMax, AsyncProp.BytesRead)
End Sub

ActiveX DLL 프로젝트와 EXE 프로젝트를 같은 프로젝트 그룹에 추가하게 되면 EXE 프로젝트에서 ActiveX DLL 프로젝트에서 DLL을 생성하지 않아도 참조할수 있게 된다.


다른 클래스 프로젝트도 마찬가지이다.

+ Recent posts