아래 설명 자료는 MSDN의 내용을 발췌하여 예제를 작성한 내용입니다. 검색보다는 항상 MSDN 문서를 보는 습관을 가집시다.

Now, Date, Year, Month, Day, Time, Hour, Minute, Second 등의 사용이 간단한 함수에 대한 설명은 따로 하지 않겠습니다.
하지만 자주 사용하는 함수이므로 반드시 숙지하시기 바랍니다.


Weekday 함수

설명
요일을 나타내는 정수를 반환합니다.

구문
Weekday(date, [firstdayofweek])

firstdayofweek 를 생략하면 vbSunday(일요일)를 기준으로 정수를 반환합니다.
반환된 값이 1이면 일요일, 2이면 월요일, 3이면 화요일... 7이면 토요일 이런 식이죠.

예제
Debug.Print Weekday(now)
Debug.Print DatePart("w", Now)
Debug.Print Choose(Weekday(Now), "일", "월", "화", "수", "목", "금", "토")




WeekDayName 함수

설명
지정된 요일을 나타내는 문자열을 반환합니다.

구문
WeekDayName(weekday, [abbreviate], [firstdayofweek])

MSDN에 선택적 인수 표시가 잘못되었네요.
weekday에 정수형(1~7) 을 입력하면 요일명을 반환합니다.
abbreviate는 True, False(기본값) 값을 가지며 True 설정 시 요일명의 반환을 약어로 합니다.(일, 월, 화, ... 토)

예제
Debug.Print WeekdayName(Weekday(Now))




DateAdd 함수

설명
지정된 시간 간격을 추가한 날짜를 반환합니다.

구문
DateAdd(interval, number, date)

각 인수가 가지는 설명자료는 MSDN을 참고하세요.
서점에서 도서를 대여할때 대여한 날짜로부터 몇일 이내에 반납해야하는 반납예정일을 구할때.. 이런경우 사용되어지겠네요.

예제
Debug.Print DateAdd("d", 1, Now)    '오늘날짜에 1일 더하기 반환
Debug.Print Now + 1




DateDiff 함수

설명
두 날짜 사이의 간격 수를 반환합니다.

구문
DateDiff(interval, date1, date2 [,firstdayofweek[, firstweekofyear]])

각 인수는 날짜함수가 거의 동일하므로 한번쯤 읽어봐 두시면 눈에 익습니다.
서점에서 반납예정일을 넘어 반납하는 경우 연체한 날짜를 구할때 쓰일 수 있겠네요.
설명을 풀어써 보자면 
두 날짜(date2 - date1) 사이의 간격(interval) 수를 반환합니다. 고로 앞에오는 date1이 클 경우 음수가 나오게 됩니다.
단순하게 차이만을 구하려면 반환되는 값에 Abs(절대값)함수를 적용하면 되겠죠?

예제
Debug.Print DateDiff("d", Now, Now + 1)




DateSerial 함수

설명
지정된 년, 월, 일의 Date 하위 형식인 Variant를 반환합니다.

구문
DateSerial(year, month, day)

지정한 각 인수의 상대적인 날짜를 구할 수 있습니다. 아래 링크 참고


예제
Debug.Print DateSerial(2013, 3, 1 - 1)    '결과는 2013-02-28




TimeSerial 함수

설명
지정된 시, 분, 초의 Date 하위 형식인 Variant를 반환합니다.

구문
TimeSerial(hour, minute, second)

지정한 각 인수의 상대적인 시간을 구할 수 있습니다. DateSerial과 비슷하죠?

예제
Debug.Print TimeSerial(18, 0 + 5, 0)   '결과는 오후 6:05:00




DatePart 함수

설명
주어진 날짜의 지정된 부분을 반환합니다.

구문
DatePart(interval, date[, firstdayofweek[, firstweekofyear]])

잘 사용하지는 않지만 있다는 정도는 알고 넘어갑시다.

예제
     Debug.Print DatePart("q", Now)    '분기
Debug.Print DatePart("d", Now)    '날짜
Debug.Print Day(Now)                 '같은 표현식(대부분 이렇게 쓰죠) Year, Month, Day, Hour, Minute, Second




위에 나열한 함수 외에 DateValue, TimeValue 함수 등이 있고 이런 함수도 있다더라 정도만 아시면 되겠습니다.


Tip.
Format 함수를 사용하여 날짜표시 형식을 변경할 수 있습니다.

예제
Debug.Print Format(Now, "YYYY-MM-DD HH:NN:SS")

수에 매개변수를 전달할 때 여러개의 매개변수를 전달할 수 있도록 매개변수목록 을 넘겨줄 수 있을까?
예를 들어 넘겨받은 매개변수의 합을 구하는 Sum 함수가 있다고 가정하면

Private Function Sum(ByVal a As Long, ByVal b As Long, ByVal c As Long) As Long
  Sum = a + b + c
End Function

위와 같이 작성해 보았다. 그런데, 10개의 매개변수가 있다면? 혹 50개의 매개변수가 있다면??
이러한 경우 ParamArray 키워드를 사용하면 쉽게 해결하여 위 코드를 아래와 같이 바꿀 수있다.

Private Function Sum(ParamArray iNums() As Variant) As Long
  Dim lResult   As Long
  Dim i         As Long
  On Error Resume Next
  For i = 0 To UBound(iNums)
    lResult = lResult + Val(iNums(i))
  Next i
  Sum = lResult
End Function


Tip.
ParamArray는 적용할 수 있는 몇가지 적용규칙이 있습니다.

1. 매개 변수 배열을 하나만 정의할 수 있으며 마지막 인수 이어야 합니다.
2. 매개 변수 배열 앞에 오는 인수는 Optional 이어서는 안됩니다.
2. ParamArray 키워드는 Optional, ByVal, ByRef 과 같이 사용될 수 없습니다.

Line함수를 이용하여 아래와 그림판과 같이 선그리기를 해보겠습니다.





프로젝트를 한개 열고 아래 그림과 같이 컨트롤을 배치합니다.

그림을 그릴 PictureBox 1개, 그린 그림을 저장할 수 있게 CommandBox 1개, 저장경로를 표시할 TextBox 1개





폼에 다음과 같이 입력합니다.


Private Sub Form_Load()

  Command1.Caption = "Save"

  Text1.Text = "c:\그림.bmp"

  Picture1.AutoRedraw = True

  Picture1.ForeColor = vbBlack

  Picture1.BackColor = vbWhite

End Sub


Private Sub Picture1_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)

  If Button = vbLeftButton Then

    Picture1.CurrentX = X: Picture1.CurrentY = Y

  End If

End Sub


Private Sub Picture1_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)

  If Button = vbLeftButton Then Picture1.Line -(X, Y)

End Sub


Private Sub Command1_Click()

  SavePicture Picture1.Image, Text1.Text

End Sub


작성된 내용이 너무 하네요.. 죄송합니다.


Tip.

MouseMove 이벤트에 마우스 왼쪽 버튼을 눌렀을때 라인을 그리는 Picture1.Line -(X, Y)을

Picture1.Line -(X, Y), , B 또는 Picture1.Line -(X, Y), , BF 로 바꾸어 보면 더욱 재밌는 모양이 만들어집니다.

MSDN을 참고하여 각 인수의 설명을 참고하시기 바랍니다.


DDE(Dynamic Data Exchange) 란 일종의 IPC(Interprocess Communication)로 공유 메모리를 사용하여
프로그램 간 통신 할 수 있는 기술이다.
현재는 잘 사용하지 않는 기술이고 닷넷에서는 지원하지 않는 구시대적인 기술이지만,
VB6에서 기본적으로 제공하는 기능이 있고 이를 이용하면 손쉽게 적용할 수 있으니 알아두면 유용합니다.
여기에서는 VB6에서 DDE를 이용하여 "이런것도 있다." 정도의 내용만 설명하였고 더 자세한 내용이나 예제는 검색을 통해
정보를 얻으시길 바랍니다.

MSDN에서 DDE 관련 메서드와 속성을 살펴보면 DDE대화 라는 표현을 쓰는데 기능, 기술 보다는 좀 다감하네요.
대화라는 단어에서 알 수 있듯이 통신을 하기위해선 서버와 클라이언트가 있겠죠?

서버가 되는 프로그램을 먼저 작성해 보겠습니다.
프로젝트를 한개 생성하고 "DDEHost" 로 프로젝트명을 수정합니다. 폼의 식별을 위해 Caption값도 "DDEHost"로 합니다.
이제 DDE 대화를 위한 필요 속성을 살펴 보겠습니다. 
폼의 LinkMode와 LinkTopic 이 보이는데 MSDN에서 검색하여 한번 훓어보시기 바람니다.

LinkMode 의 설명란을 보면
"DDE 대화에 사용된 연결 형태를 반환하거나 설정하고 연결을 활성화시킵니다." 라고 되어있고, MSDN에 보니
DDE 확인의 원본(서버)으로 사용되는 LinkMode 의 값은 vbLinkNone(사용안함), vbLinkSource(사용함) 두가지가 있네요.


 상수 

 설정 

 설명 
 VbLinkNone

 0

 (기본값) 영 — DDE대화가 없습니다. 대상응용프로그램은 항목처럼 원본 폼과 함께 대화를 시작할 수 없습니다. 그리고 응용 프로그램 또한 폼에 데이터를 송신 할 수 있습니다. 디자인 모드에서 LinkMode가 0이면 실행 모드에서 1(원본)으로 바꿀 수 없습니다.

 VbLinkSource

 1

 원본 — 폼의 Label, PictureBox, 이나 TextBox 컨트롤이 폼과 함께 DDE 확인을 설치하는 대상 응용 프로그램에 데이터를 제공하도록 허용합니다. 그런 연결이 존재한다면 Visual Basic은 자동적으로 대상에 컨트롤의 내용이 바뀔 때 마다 통보해줍니다. 그리고 대상 응용 프로그램은 폼의 Label, PictureBox 또는 TextBox 컨트롤에 데이터를 송신할 수 있습니다. 만약 LinkMode가 디자인 모드에서 1(원본)이라면 그것을 0으로 바꿀수 있으며 실행 모드로 돌아갈 수 있습니다.



DDE 확인의 원본(서버)로 사용할 것이니 vbLinkSource 라고 설정해야겠죠. 파란색으로 칠해 놓은 부분을 보니 실행모드에서는
속성값 변경이 안되며 디자인 모드에서 설정해야한다는걸 알 수있습니다.
그럼, 디자인 모드에 있는 폼의 LinkMode 값을 "1-원본"로 수정 합니다.
LinkTopic 값은 "Form1" 상태 그대로 둡니다.(이에 대한 설명은 나중에 하도록 하겠습니다.)

이제 통신을 할 텍스트박스 한개를 폼에 가져다 놓고 프로젝트를 저장합니다. EXE파일로 컴파일도 하구요. 
이제 서버쪽 프로그램은 끝났습니다.
이게 뭐야? 장난하는건가? 뭔 통신을 한다는건지.. 하는 분을 위해 빠르게 진행하겠습니다.^^


DDE 확인의 대상(클라이언트)로 사용할 프로젝트를 새롭게 열겠습니다.
프로젝트 명칭은 상관없지만 그래도 Project1이라는 무식한 이름보다는 "DDEClient" 라는 이름으로 줘 보겠습니다.
폼에 대화의 대상이 되는 텍스트박스를 한개 두고 타이머를 한개 가져다 놓고 아래 코드를 복사합니다.

Private Sub Form_Load()

  Text1.LinkItem = "Text1"

  Text1.LinkTopic = "DDEHost|Form1"

  Text1.LinkTimeout = 50

  Timer1.Interval = 100

  Timer1.Enabled = True

End Sub


Private Sub Timer1_Timer()

  On Error GoTo errHandler

  Text1.LinkMode = vbLinkAutomatic

  Me.Caption = "Connected"

  Exit Sub

errHandler:

  Me.Caption = "Wait"

End Sub


DDE 확인의 대상(클라이언트)로 사용할 프로젝트를 새롭게 열겠습니다.
프로젝트를 저장하고 EXE파일로 컴파일도 합니다.

컴파일한 두개의 프로그램이 만들어져 있죠? "DDEHost" 와 "DDEClient" 프로그램을 각각 띄워놓은 후 
"DDEHost" 쪽 텍스트박스의 내용을 변경해 봅니다. "DDEClient" 쪽 텍스트박스의 변화가 있나요?

이렇게 간단하게 두 프로그램 간에 통신이 가능하도록 해주는데 아쉽게 TextBox, Label, PictureBox 컨트롤만 지원한답니다.
이것만 가지고도 충분한 데이터 전달이 이루어질 수 있으니 응용은 직접해보시기 바람니다.

DDE 확인의 대상(클라이언트)에서 사용된 텍스트박스 속성을 보니
LinkItem, LinkTopic, LinkTimeout, LinkMode 가 있고 LinkMode에 대한 설명은 위에서 하였지만 대상이 되어지는 컨트롤에 적용되는 값은 아래와 같이 다릅니다.


 상수

 설정 

 설명 
 VbLinkNone  0  (기본값) 없음 — DDE 대화가 없습니다.
 VbLinkAutomatic

 1

 자동 — 연결된 데이터가 변할 때마다 대상 컨트롤이 업데이트됩니다.
 VbLinkManual  2  수동—LinkRequest가 호출될 때만 대상 컨트롤이 업데이트됩니다. 
 VbLinkNotify  3  통보— LinkNotify 이벤트는 연결된 데이터가 변할 때마다 일어납니다. 그러나 대상 컨트롤은 LinkRequest메서드가 호출될 때만 업데이트됩니다.


LinkItem 은 DDE확인의 원본(서버)에서 사용한 컨트롤인 텍스트박스의 이름을 기입하구요
LinkTimeout는 대화의 응답을 기다리는 시간을 설정하는데 1/10 초 단위로 지정할 수 있으며 기본값은 50(5초)를 가집니다.

LinkTopic 는 위에서 설명을 안했는데 이것도 원본(서버)과 대상(클라이언트)에서의 값이 틀립니다.
먼저 속성의 설명란을 보면 
"원본 응용 프로그램과 대상 컨트롤의 항목을 반환하거나 설정합니다." 라고 되어있네요.
원본에서는 응용프로그램을 대상에서는 컨트롤의 항목을... 이란 얘기네요.

DDE확인의 원본(서버)에서 Form의 LinkTopic 값을 "Form1" 으로 그냥 두자고 한걸 기억하시겠죠? 
원본에서의 값은 이같이 원본 연결에 필요한 문자열로 구성하면 됩니다.

DDE확인의 대상(클라이언트)의 컨트롤에서 원본으로 연결을 하기 위해서도 LinkTopic 값을 입력하는데
VB6에서는 파이프라인('|') 를 구분문자로 하여 [원본의 프로젝트명]|[원본의 LinkTopic값] 과 같이 값을 가지게 됩니다.

MSDN 을 참고하자면 MS Excel 에서는 아래와 같이 파이프라인('|') 과 느낌표('!') 를 사용하고 
application|topic!item

MS Word 에서는 파이프라인('|')이나 느낌표('!')를 사용하지 않고 스페이스(' ')로 구분하는게 다름니다.
application topic item


단하게 VB6에서 DDE기능을 이용한 데이터의 전달을 해보았는데 이 외에도 아래 이벤트와 
(LinkOpen, LinkClose, LinkError, LinkExecute)
메서드들
(LinkPoke, LinkRequest, LinkSend)
을 참고하여 검색해 보면 더욱 많은 정보를 찾을 수 있을 겁니다.

현재 Desktop 이름을 알고 싶을때 아래 코드를 참고하자.

GetDesktopName와 같이 함수형태로 만들어 놓으면 호출시 문자열값을 리턴한다.



Private Declare Function GetUserObjectInformation Lib "user32" _

                  Alias "GetUserObjectInformationA" _

                        (ByVal hObj As Long, _

                         ByVal nIndex As Long, _

                         pvInfo As Any, _

                         ByVal nLength As Long, _

                         lpnLengthNeeded As Long) As Long


Private Declare Function GetThreadDesktop Lib "user32" _

                        (ByVal dwThread As Long) As Long


Private Declare Function GetCurrentThreadId Lib "kernel32" () As Long


Private Const UOI_FLAGS     As Long = 1

Private Const UOI_NAME      As Long = 2

Private Const UOI_TYPE      As Long = 3

Private Const UOI_USER_SID  As Long = 4



Private Function GetDesktopName() As String


  Dim hDesktop    As Long

  Dim sBuffer     As String

  Dim lLength     As Long

  

  hDesktop = GetThreadDesktop(GetCurrentThreadId)


  If hDesktop = 0 Then Exit Function


  GetUserObjectInformation hDesktop, UOI_NAME, ByVal vbNullString, 0&, lLength


  sBuffer = Space(lLength)


  GetUserObjectInformation hDesktop, UOI_NAME, ByVal sBuffer, lLength, lLength


  If InStr(sBuffer, Chr(0)) Then

    GetDesktopName = Left(sBuffer, InStr(sBuffer, Chr(0)) - 1)

  End If

  

End Function



'VB6 > Function' 카테고리의 다른 글

마우스커서가 위치한 윈도우 핸들 구하기  (0) 2013.03.27
대기시간 함수  (0) 2013.03.27

UserControl에서 지원하는 AsyncRead 메서드를 이용하여 웹이미지를 가져오는 컨트롤을 만들어보겠습니다.
웹 이미지 뿐만 아니라 이를 이용하면 쉽게 파일 업데이트 기능도 만들 수 있습니다.(검색.. 검색)

예를 들어 고객관리 프로그램이 있는데 고객의 기본정보는 데이터베이스에서 가져오고 이용자의 키값으로 웹서버에 사진이미지나
명함 이미지를 가져올 경우... 
이미지고 뭐고 바이너리한 데이터를 전부 데이터베이스에 넣어놓고 가져올 수 있게 만들면 되잖아.. 
뭐.. 예를 들어본거니 이러한 경우가 있다고 가정합시다. 웹이 아닌경우일 뿐이지 실제로 이러한 경우는 꽤 있는편입니다...

프로젝트를 한개 만들어서 사용자 정의 컨트롤을 한개 추가합니다.
추가된 사용자 정의 컨트롤에 PictureBox 한개를 놓고 아래 소스를 붙여넣기 합니다.

Private Sub UserControl_Initialize()
  Picture1.AutoSize = True
  Picture1.Visible = False
End Sub

Private Sub UserControl_AsyncReadComplete(AsyncProp As AsyncProperty)
  On Error Resume Next
  If AsyncProp.StatusCode <> vbAsyncStatusCodeEndDownloadData Then Exit Sub
  If AsyncProp.BytesRead <= 0 Then Exit Sub
  If AsyncProp.AsyncType = vbAsyncTypePicture Then
    Picture1.Picture = AsyncProp.Value
    UserControl.Picture = Picture1.Picture
    UserControl.Width = Picture1.ScaleWidth
    UserControl.Height = Picture1.ScaleHeight
  End If
End Sub

Public Sub AsyncImage(ByVal Url As String)
  On Error Resume Next
  UserControl.AsyncRead Url, vbAsyncTypePicture
End Sub


도구상자에서 방금 만들어 놓은 사용자 정의 컨트롤을 폼에 올려 놓고 CommandBox 도 한개 가져다 놓습니다.
버튼 Click 이벤트에 다음과 같이 코드를 입력합니다.

UserControl11.AsyncImage "http://buery.co.kr/parking/title.jpg"

정상적인 경로를 넘겨주면 AsyncRead를 통해 전달된 이미지를 컨트롤을 통해 볼 수 있습니다.
Event 를 정의하여 읽어오기가 진행중인지 완료되었는지 실패하였는지 등.. 도 구현가능하겠죠..


날짜함수중 DateSerial과 DateAdd 함수를 이용하여 해당월에 마지막 날짜을 알아오는 방법을 알아보겠습니다.

MSDN 자료를 보면


DateSerial 함수

지정된 년, 월, 일의 Variant(Date) 값을 반환합니다.


구문

DateSerial(year, month, day)

DateSerial 함수 구문은 다음과 같은 명명된 인수로 되어 있습니다.


 구성 

설명 

 year

필수. Integer. 100에서 9999 까지의 수 또는 수식

 month

필수. Integer. 모든 수식

 day

필수. Integer. 모든 수식

참고

예를 들어 1991년 12월 31일처럼 어떤 날짜를 지정하려면 각 DateSerial 인수의 숫자는 해당 인수의 허용 범위 안에 있어야 합니다. 즉, 일은 1 – 31이며, 월은 1 - 12입니다. 그러나 특정 날짜의 앞 뒤에 년, 월, 일 등을 나타내는 수식을 사용하여 각 인수의 상대 날짜를 지정할 수 있습니다.

다음은 특정 일자를 지정하지 않고 수식을 사용한 예제입니다. DateSerial 함수는 1990의 10년 전(1990-10) 8월의 2개월 전(8-2) 첫째 날에서 하루를 뺀(1-1), 즉 1980년 5월 31일을 반환합니다.

DateSerial(1990 - 10, 8 - 2, 1 - 1)

year 인수의 값이 0–99 사이의 값이면 1900부터 1999년까지로 해석되며 그 밖의 모든 year 인수는 1800년처럼4 자릿수의 완전한 연도를 사용합니다.

인수가 허용되는 범위를 넘으면 적절한 상위 단위로 변환하여 계산합니다. 예를 들어 35일을 지정하면 적용 연도에 따라 1개월 며칠로 계산합니다. 그러나 한 인수가 -32,768 - 32,767 범위를 넘는 인수이거나 세 인수를 사용하여 지정된 날짜가 허용 범위를 넘을 경우 오류가 발생합니다.


DateAdd 함수

특정 시간 간격을 포함한 Variant(Date) 값을 반환합니다.


구문

DateAdd(interval, number, date)

DateAdd 함수 구문은 다음과 같은 명명된 인수로 되어 있습니다.


 구성 요소

설명 

 interval

필수. 문자식을 사용하여 시간 간격을 표시합니다.

 number

필수. 수식을 사용하여 날짜에 시간 간격을 가감합니다. 양수(이후 시간을 계산하는 경우)와 음수(이전 시간을 계산하는 경우) 모두 사용 가능합니다.

 day

필수. Variant(Date) 형의 날짜에는 시간 간격이 가감됩니다.


설정

interval 인수의 설정은 다음과 같습니다.


 구성 

설명 

 yyyy 연도
 q 분기 
 m

 y 일(일년 기준) 
 d 일 
 w

요일

 ww 주 
 h

시간

 n 분 
 s


참고

날짜에 특정 시간을 더하거나 뺄 때 DateAdd 함수를 사용합니다. 예를 들어 현재 시간부터 45분 이후 시간이나 현재 일로부터 30일 이후의 날짜를 계산할 때 DateAdd 함수를 사용합니다.

date에 날짜를 더할 때 연("y"), 일("d")이나 요일("w")을 사용합니다.

DateAdd 함수는 틀린 날짜 값은 반환하지 않습니다. 다음은 95년 1월 31일에 1개월(30일)을 더한 예제입니다.

DateAdd("m", 1, "95 1 31")

위의 경우 DateAdd 함수는 95년 2월 31일이 아닌 95년 2월 28일을 반환합니다. date가 96년 1월 31일인 경우는 윤년이기 때문에 96년 2월 29일을 반환합니다.

계산한 날짜가 100년을 넘어가면 오류가 발생합니다. 실제 date보다 많은 연도를 가감했기 때문입니다.

number가 Long 값이 아니면 가까운 정수값으로 반올림한 후 계산합니다.

메모 DateAdd 함수의 반환값 형식은 date 인수에 전달된 형식 대신 [제어판] 설정에 의해 결정됩니다.



먼저 DateSerial 함수를 살펴보겠습니다.

예제에서와 같이 인수가 허용하는 범위를 넘으면 적절한 상위단위로 변환하여 계산한다고 하는 설명이 있는데 이를 이용하여 

2013년 02월 달의 마지막일을 구하려는 수식은

DateSerial(2013, 3, 1 - 1)    '결과는 2013-02-28 

즉 매월 0일은 계산식에 의해 이전달의 마지막일을 구할 수 있음을 알 수 있습니다.


다음으로 DateAdd 함수를 보면

날짜를 더하거나 뺄때 사용하는 함수로 이도 마찬가지로 마지막일을 구하려는 다음월을 인수로 하여 1일을 빼면 동일한 결과를

얻을 수 있습니다.

DateAdd("d", -1, "2012-03-01")    '결과는 2013-02-28 


폼이 움이직다가 화면 가장자리에 닿으면 다른 방향으로 튀게 하여 화면 안에서 움직이는 폼을 만들어 보겠습니다.

폼에 타이머를 한개 가져다 두고 아래 코드를 작성하면 됩니다.

화면 가장자리에 닿았는지에 따라 mMoveX와 mMoveY가 다음 이동방향을 결정하는 부분이 중요합니다.



Private mMoveX  As Long

Private mMoveY  As Long


Private Sub Form_Click()

  Unload Me

End Sub


Private Sub Form_Load()


  mMoveX = 1

  mMoveY = 1


  Timer1.Enabled = True

  Timer1.Interval = 1

  

End Sub


Private Sub Timer1_Timer()

  

  Const MoveInterval  As Long = 10

  

  Dim lLeft     As Long

  Dim lTop      As Long

  Dim lRight    As Long

  Dim lBottom   As Long

  


  lLeft = Me.Left

  lTop = Me.Top

  lRight = Me.Left + Me.Width

  lBottom = Me.Top + Me.Height


  

  If lLeft <= 0 Or lRight >= Screen.Width Then

    mMoveX = mMoveX * -1

  End If

  

  If lTop <= 0 Or lBottom >= Screen.Height Then

    mMoveY = mMoveY * -1

  End If

  

  Me.Move Me.Left + (MoveInterval * mMoveX * 15), Me.Top + (MoveInterval * mMoveY * 15)


End Sub



다음은 동일한 기능을 수행하도록 API로 작성해보았습니다.



Private Declare Function GetWindowRect Lib "user32" _

                        (ByVal hwnd As Long, _

                         lpRect As RECT) As Long


Private Declare Function GetClientRect Lib "user32" _

                        (ByVal hwnd As Long, _

                         lpRect As RECT) As Long


Private Declare Function GetDesktopWindow Lib "user32" () As Long


Private Declare Function SetWindowPos Lib "user32" _

                        (ByVal hwnd As Long, _

                         ByVal hWndInsertAfter As Long, _

                         ByVal x As Long, _

                         ByVal y As Long, _

                         ByVal cx As Long, _

                         ByVal cy As Long, _

                         ByVal wFlags As Long) As Long


Private Const SWP_NOSIZE = &H1


Private Type RECT

        Left As Long

        Top As Long

        Right As Long

        Bottom As Long

End Type



Private mMoveX  As Long

Private mMoveY  As Long


Private Sub Form_Click()

  Unload Me

End Sub


Private Sub Form_Load()


  mMoveX = 1

  mMoveY = 1


  Timer1.Enabled = True

  Timer1.Interval = 1

  

End Sub


Private Sub Timer1_Timer()

  

  Const MoveInterval  As Long = 10

  

  Dim ClientRect As RECT

  Dim WindowRect As RECT


  GetClientRect GetDesktopWindow, ClientRect


  GetWindowRect Me.hwnd, WindowRect


  

  If WindowRect.Left <= 0 Or WindowRect.Right >= ClientRect.Right Then

    mMoveX = mMoveX * -1

  End If

  

  If WindowRect.Top <= 0 Or WindowRect.Bottom >= ClientRect.Bottom Then

    mMoveY = mMoveY * -1

  End If

 

  SetWindowPos Me.hwnd, 0&, WindowRect.Left + (MoveInterval * mMoveX), _

                            WindowRect.Top + (MoveInterval * mMoveY), 0, 0, SWP_NOSIZE

  

End Sub


폼에 위치나 크기정보를 가져오기 위해 GetClientRect와 GetWindowRect를 사용하였네요.


폼 위치, 크기 구하기



구멍뚫린 폼을 만들어 볼까 합니다. 

예를들어 캡순이 프로그램 처럼 지정된 영역안에 있는 화면만 캡춰하여 이미지로 저장할 수 있는 기능을 만들고자 할때 가운데가 비어있는 사각틀을 만들어야 되겠죠?  그래서 그 사각틀을 만들어 볼까 합니다.


사각틀을 만드는 다른방법으로 SetLayeredWindowAttributes 를 사용하여 해당 색상을 투명하게 만들어 작업할 수도 있습니다.


폼 투명도 주기



아래 그림과 같이 윈도우 폼은 일반적으로 타이틀이나 테두리 부분이 있는 비클라이언트 영역과 컨트롤 등을 배치하여 작업을

하는 클라이언트 영역으로 나뉩니다.




여기에서는 폼사이즈에 변경에 관계없이 클라이언트 영역만 안보이게 하여 아래 그림과 같이 만들어 보겠습니다.




Private Declare Function GetWindowRect Lib "user32" _

                        (ByVal hwnd As Long, _

                         lpRect As RECT) As Long

                         

Private Declare Function GetClientRect Lib "user32" _

                        (ByVal hwnd As Long, _

                         lpRect As RECT) As Long

                         

Private Declare Function CreateRectRgn Lib "gdi32" _

                        (ByVal X1 As Long, _

                         ByVal Y1 As Long, _

                         ByVal X2 As Long, _

                         ByVal Y2 As Long) As Long

                         

Private Declare Function OffsetRgn Lib "gdi32" _

                        (ByVal hRgn As Long, _

                         ByVal x As Long, _

                         ByVal y As Long) As Long

                         

Private Declare Function CombineRgn Lib "gdi32" _

                        (ByVal hDestRgn As Long, _

                         ByVal hSrcRgn1 As Long, _

                         ByVal hSrcRgn2 As Long, _

                         ByVal nCombineMode As Long) As Long

                         

Private Declare Function SetWindowRgn Lib "user32" _

                        (ByVal hwnd As Long, _

                         ByVal hRgn As Long, _

                         ByVal bRedraw As Boolean) As Long

                         

Private Declare Function DeleteObject Lib "gdi32" _

                        (ByVal hObject As Long) As Long


Private Type RECT

        Left As Long

        Top As Long

        Right As Long

        Bottom As Long

End Type


Private Const RGN_AND = 1

Private Const RGN_OR = 2

Private Const RGN_XOR = 3

Private Const RGN_DIFF = 4

Private Const RGN_COPY = 5


Private Sub Form_Resize()


  Const Degree    As Long = 0


  Dim WindowRect  As RECT

  Dim ClientRect  As RECT

  Dim hRgn1       As Long

  Dim hRgn2       As Long

  Dim lMoveX      As Long

  Dim lMoveY      As Long


  GetWindowRect Me.hwnd, WindowRect


  GetClientRect Me.hwnd, ClientRect


  lMoveX = ((WindowRect.Right - WindowRect.Left) - ClientRect.Right) \ 2

  lMoveY = ((WindowRect.Bottom - WindowRect.Top) - ClientRect.Bottom) - lMoveX


  hRgn1 = CreateRectRgn(0, 0, WindowRect.Right - WindowRect.Left, WindowRect.Bottom - WindowRect.Top)


  hRgn2 = CreateRectRgn(0, 0, ClientRect.Right - Degree * 2, ClientRect.Bottom - Degree * 2)


  OffsetRgn hRgn2, lMoveX + Degree, lMoveY + Degree


  CombineRgn hRgn1, hRgn1, hRgn2, RGN_XOR


  SetWindowRgn Me.hwnd, hRgn1, True


  DeleteObject hRgn1

  DeleteObject hRgn2


End Sub

 

폼의 비 클라이언트 영역을 포함한 크기로 Region을 만들고(hRgn1), 구멍의 크기를 클라이언트 영역으로 잡고(hRgn2),

OffsetRgn을 이용하여 hRgn2의 위치를 타이틀과 테두리의 크기를 뺀 위치만큼 이동시키고 이를 CombineRgn으로 XOR하여 

겹치지 않는 영역만 남게하여 폼에 적용하고 생성한 Region을 지우는 겁니다.


GetWindowRect, GetClientRect의 설명은 아래 링크를 참고하세요. 

폼 크기, 위치 구하기

 

Tip.

Form_Resize 안에 Degree 값을 증가시키면 사각틀 안쪽이 좁아지게 됩니다.





'VB6 > Interface' 카테고리의 다른 글

폼 타이틀바 Show/Hide  (0) 2013.03.28
바탕화면 아이콘 Show/Hide  (0) 2013.03.28
폼 위치, 크기 구하기  (0) 2013.03.27
폼 투명도 주기  (0) 2013.03.27
폼 타이틀바 이동효과  (0) 2013.03.26

오스크 등의 프로그램을 위해 윈도우 타이틀바를 필요치 않으면 Form 속성중 BorderStyle을 0으로 설정하는데

런타임시에 Show/Hide를 하고 싶을때 아래 코드를 참고하자.



Private Declare Function GetWindowLong Lib "user32" _

                  Alias "GetWindowLongA" _

                        (ByVal hwnd As Long, _

                         ByVal nIndex 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 Declare Function GetWindowRect Lib "user32" _

                        (ByVal hwnd As Long, _

                         lpRect As RECT) As Long


Private Declare Function SetWindowPos Lib "user32" _

                        (ByVal hwnd As Long, _

                         ByVal hWndInsertAfter As Long, _

                         ByVal x As Long, _

                         ByVal y As Long, _

                         ByVal cx As Long, _

                         ByVal cy As Long, _

                         ByVal wFlags As Long) As Long


Private Const GWL_STYLE = (-16)


Private Const WS_CAPTION = &HC00000 ' WS_BORDER Or WS_DLGFRAME

Private Const WS_MAXIMIZEBOX = &H10000

Private Const WS_MINIMIZEBOX = &H20000

Private Const WS_THICKFRAME = &H40000

Private Const WS_SYSMENU = &H80000


Private Const SWP_NOSIZE = &H1

Private Const SWP_NOMOVE = &H2

Private Const SWP_NOZORDER = &H4

Private Const SWP_FRAMECHANGED = &H20


Private Type RECT

    Left As Long

    Top As Long

    Right As Long

    Bottom As Long

End Type



Private Sub Command1_Click()

  SetWindowLong Me.hwnd, GWL_STYLE, _

                GetWindowLong(Me.hwnd, GWL_STYLE) And Not (WS_CAPTION)


  SetWindowPos Me.hwnd, 0, 0, 0, 0, 0, _

                SWP_NOSIZE Or SWP_NOMOVE Or SWP_NOZORDER Or SWP_FRAMECHANGED

End Sub


Private Sub Command2_Click()

  SetWindowLong Me.hwnd, GWL_STYLE, _

                GetWindowLong(Me.hwnd, GWL_STYLE) Or (WS_CAPTION)


  SetWindowPos Me.hwnd, 0, 0, 0, 0, 0, _

                SWP_NOSIZE Or SWP_NOMOVE Or SWP_NOZORDER Or SWP_FRAMECHANGED

End Sub


Private Sub Form_Load()

  Command1.Caption = "Hide"

  Command2.Caption = "Show"

End Sub


Tip.
코드를 실행시켜보면 단순히 타이틀만 없어지고 사이즈 조절은 된다.
BorderStyle을 없음(0)으로 설정한 것과 같이 하려면 WS_CAPTION을 WS_CAPTION OR WS_THICKFRAME 로 
변경하면 된다.

'VB6 > Interface' 카테고리의 다른 글

폼에 보여줄 영역 만들기(구멍난 폼)  (0) 2013.03.28
바탕화면 아이콘 Show/Hide  (0) 2013.03.28
폼 위치, 크기 구하기  (0) 2013.03.27
폼 투명도 주기  (0) 2013.03.27
폼 타이틀바 이동효과  (0) 2013.03.26

+ Recent posts