모두 아시다시피, VBScript에서는 Data Type이 존재하지 않습니다.
기본적으로 모든 Data는 [Variant] Type입니다.
VBA와도 조금 다르네요...

하지만, 대다수의 Class들은 "CreateObject" 키워드를 통해 사용은 가능합니다.

Dim obj
Set obj = CreateObject("ADODB.Recordset")

하지만, DB를 핸들링하는 데 많이 사용하는 ADODB.Command는 사용이 불가능합니다.

그래서, ADODB.Recordset를 통해야 하는 데요.
String(문자열)로 Query를 작성하는 데서, 꽤나 애를 먹었습니다.

그래서 정리했습니다 ^^;

Dim strQuery
Dim objRs
‘ EXECUTE가 아닌 ‘EXEC’를 사용한다. 'EXECUTE'를 사용하면 아니 아니 아니됩니다~~
strQuery = "EXEC " & STORED_PROC_NAME
‘ Number(Int, Float)등의 변수는 그냥 문자열로 변환 후에 할당해주면 됩니다.
strQuery = strQuery & " @PARAM1 = " & INT_VALUE
‘ 하지만 STRING 변수는 따옴표(‘)로 묶어주며, 다수의 변수를 요구하는 SP의 경우, 쉼표(,)로 구분하면 됩니다.
strQuery = strQuery & ", @PARAM2 = '" & STR_VALUE & "'"

Set objRs = CreateObject("ADODB.Recordset")
' 찾다가 찾다가 가장 승질 뻗친 부분인데요, 옵션을 아무것도 넣어주면 안됩니다. Default로 된 것을 넣어줘도 안되었던 기억이 있네요.
' 그냥 아무 옵션을 걸지말고 해야합니다.
objRs.Open strQuery, dbConn
Set objRs = Nothing

위에 주석으로 설명을 했습니다. ^^;

이것 때문에 한참을 고생했드랬습니다.

VBScript는 다뤄보질 않아서, 그냥 VBA와 비슷하겠거니라고 하고, 뎀볐는 데.... 이상한 곳에서 많이 막혔었네요;;

테스트 환경도 없고, 디버깅....은 어찌하는 지 몰라서, 그냥 VBA에 대놓고 코딩을 했었거든요.
몇 가지 차이점만 주의하면, VBA에서 코딩하고 테스팅해서 올리면 바로 되긴 합니다. ^^

조만간 VBScript를 작성하며, 생긴 노하우에 대해서 포스팅해보겠습니다.ㅎㅎ


덧.
아..이 개발은 웹이 베이스가 아니었습니다.
MS-SQL SERVER에 DTS(Data Transfer Service)라고 있는 데, 여기에 들어갈 서비스를 수정하는 것을 맡았었거든요.
웹이 베이스라면, 무언가를 뿌려보고 해서(C에서의 printf와 같이....) 수행 단계를 확인이나마 할 수 있었을 텐데요;;
모 별 수 없이. DB Table에 Step 데이터를 뿌려서, 그걸 확인하며 했었네요;;
여튼 이 부분은 곧! 정리해서 포스팅 하겠습니다.

'배움 > VBScript' 카테고리의 다른 글

VBScript에서 STORED PROCEDURE 사용하기  (0) 2012.03.19

순간 나를 당황하게 만든 서식

잔말말고 그것이 무엇인지 확인!!!



흐음...저 "부분/문자열"이라는 문자열은 하나의 셀에 있는 값입니다.
테두리를 보이게 할 걸 그랬네요..^^;

모...아는 게 아니니, 일단 구글링...으로 솔직히 별 어렵지 않게 찾았습니다.
  + 갈수록 검색시의 키워드 선택 감각이 발전하는 듯 합니다. 캬캬~
검색해서 찾은 게 아래의 코드 입니다.

With TargetCell.Characters(Start, Len(TargetWord)).Font 
    If IsNull(FontName) = False Then .Name = FontName 
    If IsNull(FontBold) = False Then .Bold = FontBold 
    If IsNull(FontSize) = False Then .Size = FontSize 
    If IsNull(FontColor) = False Then .ColorIndex = FontColor 
End With 
Url: http://www.vbaexpress.com/kb/getarticle.php?kb_id=743

대충 보시면, Cell 객체 안에 Characters라는 객체가 존재합니다. 그리고 Characters라는 객체는 왠지 문자열에 대한 객체일듯 하구요. 코드는 TargetCell이라는 Cell에 포함된 Characters 문자열의 Start부터 Len(TargetWord)까지의 Font를 설정해주는 코드네요. 당연스럽게 TargetWord는 실질적으로 TargetCell.Characters와 동일하겠죠.

 + VBA(Excel이든, word 든)에서는 객체라는 용어를 사용하기가 개인적으로 좀 애매합니다. VBA에서 Class를 제공하기는 하지만, 동작하는 것을 보면, 우리가 일반적으로 사용하는 C++, JAVA 등에서의 Class와는 사뭇 다른 느낌이 나거든요. 기회가 되면, 이에 대해서 썰을 한 번 풀어보도록 하겠습니다.

제가 할 것은 붉은 색으로 된 [부분/문자열]에서 [/문자열]만을 검정색으로 변경해주는 것 입니다.
   # 헙;; 위의 요구사항 예시를 잘못 만들었네요.ㅋㅋ

With ThisWorkbook.Sheets("Sheet1")
    Dim i As Integer
    For i = 0 To rowOffset
        Dim index As Integer
        Dim target As String
        target = .Range(START_CELL).Offset(i, 5).Value
        index = InStr(1, target, "/")
        If index > 0 Then
            .Range(START_CELL).Offset(i, 5).Characters(index, Len(target)).Font.Color = RGB(0, 0, 0)
        End If
    Next i
End With
코드는 간단합니다. 원하는 Cell의 문자열에서 "/"의 위치를 찾고 존재한다면, "/"부터 끝까지를 검정색으로 설정!
부분문자열에 대한 font 핸들링은 Cell에서 Characters 객체를 이용하시면 됩니다!!!
테이블 설계를 변경해야 하는 경우
해당 테이블을 사용하는 STORED PROCEDURE, STORED FUNCTION 등을 찾아야 하는 데요.
그래야 변경을 할 것인지 아닌지를 결정할 수 있고, 변경할 수 있는 범위를 가늠할 수도 있고요.
이 또한 문서화가 제대로 되어있지 않을 수 밖에 없으니..

특정 테이블을 사용하는 PROCEDURE를 찾는 쿼리입니다.

SELECT 
    DISTINCT O.NAME
FROM 
    SYSDEPENDS AS D
INNER JOIN 
    SYSOBJECTS AS O 
ON 
    D.ID = O.ID
WHERE 
    O.XTYPE = 'P' 
	AND D.DEPID = 
	    (
    	    SELECT 
    	        ID 
    	    FROM 
    	        SYSOBJECTS 
    	    WHERE 
    	        NAME = '테이블명'
	    )

한계는 존재합니다. 테이블이 정의된 CATEGORY와 동일한 CATEGORY 내에 존재하는 STORED PROCEDURE만 찾을 수 있다는 것인데요.
물론, 다른 CATEGORY에 정의된 테이블을 사용하는 게 옳은 지에 대해서는 저는 아직 잘 모르겠습니다.
다만 가급적 안하는 게 좋겠죠. 하지만 그런 경우 자체는 존재하니.ㅠㅠ
차라리 다른 CATEGORY에 존재하는 TABLE의 내용을 사용하고 싶은 경우에는 TABLE 자체를 자신의 CATEGORY로 자동으로 MIRRORING해주는 게 맞을 듯 합니다. 실시간으로 해주고 싶다면, TRIGGER도 있고, 사용이 잘 안되는 시간대에 이벤트로 변경된 것만 긁어와도 되고, 방법이야 많으니까요. ㅎㅎ

'배움 > MS-SQL' 카테고리의 다른 글

특정 테이블을 사용하는 STORED PROCEDURE 찾기  (2) 2012.03.08
TABLE COLUMN 정보 확인 QUERY  (0) 2012.03.08

DATABASE 테이블에 대한 설계 문서는 가장 중요합니다.
하지만, 실상 문서 자체가 현 상태를 제대로 설명해주는 경우는 잘 없습니다.
그래서 확인해야 할 경우가 존재하는 데요.
아래 쿼리를 사용하면 됩니다.
SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '테이블명' ORDER BY ORDINAL_POSITION
각 COLUMN이 NULLABLE인지 아닌지, 그 데이터 타입이 무엇인지 등을 확인할 수 있습니다.
그리고 덤으로 해당 테이블의 PRIMARY KEY인 COLUMN을 확인할 수 있는 QUERY도 아래에 두겠습니다.
SELECT 
    COLUMN_NAME
FROM 
    INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE 
    OBJECTPROPERTY(OBJECT_ID(CONSTRAINT_NAME), 'ISPRIMARYKEY') = 1
    AND 
        TABLE_NAME = '테이블명'
이 역시 테이블 정보를 확인하는 데, 필수적인 정보겠죠.

종종 쓸 수 밖에 없는 QUERY라서 BACKUP용도로 포스팅합니다.^^


'배움 > MS-SQL' 카테고리의 다른 글

특정 테이블을 사용하는 STORED PROCEDURE 찾기  (2) 2012.03.08
TABLE COLUMN 정보 확인 QUERY  (0) 2012.03.08
입력 화면에서 사용자가 입력한 것을 확인하기 위한 코드를 작성하였습니다.

코드1
'/***********************************************************************************
' 함수명    : CheckTextBox
' 작성자    : 정진우
' 설명      : TextBox 입력값이 존재하는 지 여부를 판단해 오류가 있을 경우, msgbox를 띄우고 false를 반환
' 리턴값    : [false] 오류 발생
' 매개변수
'           txt     : 대상 TextBox
'           title   : 대상 TextBox 갖고 있는 내용
' 이력사항
'           2011.12.20: 생성
'/***********************************************************************************
Public Function CheckTextBox(ByRef txt As TextBox, ByVal title As String, Optional ByVal isEssencial As Boolean = False, Optional ByVal length As Integer = 1000) As Boolean
    If isEssencial = True And (IsNull(txt.Text) Or txt.Text = "") Then
        MsgBox title & " 입력하세요." & Space(6), 48, "입력 오류"
        txt.SetFocus
        CheckTextBox = False
    End If
    
    If (Not IsNull(txt.Text)) And Len(txt.Text) > length Then
        MsgBox title & "에 대한 입력의 최대 길이는 " & CStr(length) & "를 넘을 수 없습니다." & Space(6), 48, "입력 오류"
        txt.SetFocus
        CheckTextBox = False
    End If
    
    CheckTextBox = True
End Function
텍스트박스가 많으니, 위의 프로시저를 만들고, 빠바박 한 화면에 포함된 모든 텍스트박스를 넘겨주면 코드도 깔끔하게 나올 것이란 판단에서였죠.ㅎㅎ
그리고 잘못된 입력 혹은 미입력 시에 나오는 Message box에 대한 문구도 통일 할 수 있으니 더욱 좋고요 ^^

아래와 같이 호출을 해서 사용하면, 호출하는 코드에서도 보기도 편하고요!!
If modDataChecker.CheckTextBox(txtBox1, "입력 텍스트 상자 1", True, 8) = False Then Exit Sub
If modDataChecker.CheckTextBox(txtBox2, "입력 텍스트 상자 2", True, 10) = False Then Exit Sub
If modDataChecker.CheckTextBox(txtBox3, "입력 텍스트 상자 3", True, 10) = False Then Exit Sub
If modDataChecker.CheckTextBox(txtBox4, "입력 텍스트 상자 4", True, 20) = False Then Exit Sub
If modDataChecker.CheckTextBox(txtBox5, "입력 텍스트 상자 5", True, 20) = False Then Exit Sub

하지만, 호출 시에 오류가 발생합니다.

* 타입 미스 매칭 에러... 타입이 다르다고 하네요 .ㅡ.ㅡ;

함수 호출 시에 넘겨주는 txtBox1도 확인해 보면, TextBox 형식이고,
작성한 함수도 위에 보시는 데로 ByRef txt as TextBox.....아무리 봐도 눈으로는 문제가 없어 보입니다.
그러면 당연히 구글링!!
http://www.mrexcel.com/forum/showthread.php?t=53911
위 url에서 바로 확인할 수 있었네요.

컨트롤을 매개변수로 받는 함수(혹은 프로시져) 작성시에는
ByRef txt As msforms.TextBox

로 매개변수를 선언해줘야 합니다.
"msforms.TextBox"
다른 형식으로도 TextBox가 선언이 되어 있나봅니다.
다른 컨트롤 컴포넌트를 사용하지도 않는 데...
다른 컨트롤에 대해 확인하는 함수에도 모두 "msforms"를 붙여줬답니다..ㅎㅎㅎ

쩝;;난감;;; 완성된 코드는 아래에...모 함수 선언만 바뀌었을 뿐입니다;
Public Function CheckTextBox(ByRef txt As msforms.TextBox, ByVal title As String, Optional ByVal isEssencial As Boolean = False, Optional ByVal length As Integer = 1000) As Boolean
    If isEssencial = True And (IsNull(txt.Text) Or txt.Text = "") Then
        MsgBox title & " 입력하세요." & Space(6), 48, "입력 오류"
        txt.SetFocus
        CheckTextBox = False
    End If
    
    If (Not IsNull(txt.Text)) And Len(txt.Text) > length Then
        MsgBox title & "에 대한 입력의 최대 길이는 " & CStr(length) & "를 넘을 수 없습니다." & Space(6), 48, "입력 오류"
        txt.SetFocus
        CheckTextBox = False
    End If
    
    CheckTextBox = True
End Function

내용 자체는 짧은 것입니다만은... 이렇게 길게 포스팅을 한 이유는 "refactoring"에 대한 것입니다.
입력 화면을 개발하는 분들이 많을 텐데요.
짧은 코드라고 하더라도, 저런 형태로 함수를 추출하고, 재사용하게 된다면, 유지보수에 엄청난 도움이 됩니다!!

짧은 코드라고 하더라도, ctrl + c, ctrl + v를 하신다면, 그 즉시 함수로 추출하는 습관을 들이세요 ^^
엑셀을 접할 때, 가장 중요한 것은 하나의 sheet는 한 형식(type)에 대한 정의로 구성하는 것으로 시작해야 한다는 것입니다.

'열(column)'과 '행(row)'로 이뤄지게끔 구성하는 것이죠.

하나의 '정보 조각', 그것을 설명할 수 있는 '설명'들로 열을 구성하고, 일련의 '정보'들을 행으로 구성하는 것이죠.

그래야지 하나의 정보가 깔끔하게 구성이 되어, 이해하기가 편하게 됩니다.

/***************************************************************************************************
* 정보 혹은 데이터에 대한 용어가 깔끔하지 않네요. 둘다 결국은 같은 사전적 의미를 가지니까요. datum이 data의 단수이지만, 잘 사용하지 않는 용어다보니..
* 그래서 위에서는 '설명'이 모여서 '정보 조각'을 이루고, 일련의 정보 조각의 모음을 '정보'라고 사용했습니다. 그래도 어렵네요;;
***************************************************************************************************/

위에서 설명한 것과 마찬가지로, 정보들은 그것을 구성하는 정보 조각들로 구분해 더욱 상세하게 풀어서 설명을 할 수 있습니다. 정보 조각들 또한 그것을 더욱 세세하게 나누어 더욱 작은 정보 조각들로 구성할 수 있구요.

필요에 따라 엑셀에도 정보들을 쪼개어서 표현할 수가 있기는 합니다.

'깊이(depth)'를 한 단계 더 두는 것인데요.

한 단계 더 깊은 것들은 보일 필요가 있을 때가 있고, 숨길 때가 있습니다.

엑셀 사용시에 흔히 사용하는 '열 숨기기' 혹은 '행 숨기기' 기능입니다. 이 기능을 통해서 행 또는 열을 숨겨서 보고자 하는 정보만을 한 번에 확인할 수 있도록 하는 거죠.

그런데, 저 기능을 사용하다보면 조금은 불편할 때가 있습니다. 일일이 행과 열을 선택해서 우클릭 후에 보이는 팝업 메뉴(혹은 컨텍스트 메뉴)를 통해서만 제어가 가능하다는 점인데요. 자주 '숨기기'하고, '숨기기 취소'하게 된다면, 여간 불편한게 아닙니다.

이런 이들을 위해서 엑셀에서 제공하는 기능이 있는 데, 바로 '윤곽'이라는 기능입니다.
일련의 행들을 하나로 묶어 '윤곽'을 설정해두면, 좌측에 나타나는 [+]와 [-]를 클릭하는 것으로 [숨기기]와 [숨기기 취소]를 할 수 있게 도와줍니다.

사용법은 다음과 같습니다.

1. 일련의 [행/열]을 선택합니다.
2. 메뉴에 [데이터] - [그룹 및 윤곽 설정] - [그룹]을 클릭하면 선택한 [행/열]이 하나의 덩어리로 구성이 됩니다.

여기서 구성된 [하나의 덩어리]가 위에서 설명한 '깊이'와 연관이 됩니다.
처음에 구성된 하나의 sheet에 있는 정보들은 기본적으로 level 1의 깊이를 가진 데이터입니다.
그리고 위의 행위를 통해 만들어진 [하나의 덩어리]는 level 2의 깊이를 가진 데이터가 됩니다.
level 2의 깊이를 가진 정보들의 내부에 다시 [덩어리]를 만들게 되면 그것은 level 3의 깊이를 가진 데이터가 되는 식이죠.

대한민국의 교육 체계를 바탕으로 설명을 드리면,
가장 표면적인 것을 '고등 교육', '중등 교육', '초등 교육'으로 나뉠 수 있습니다. 이것을 level 1으로 보도록 하겠습니다.
이를 조금더 자세히 본다면,
'고등 교육'에는 [대학]이 있고요, '중등 교육'에는 [고등학교]와 [중학교]로 구분할 수 있습니다.
'초등 교육'에는 [초등학교]가 있고요. 이는 level 2가 됩니다.
다시 이를 나누면, [대학]에는 박사 과정, 석사 과정, 학사 과정 그리고 전문 학사 과정으로 나뉠 수 있고요. 이것이 level 3가 되겠죠.
그 아래에는 각 학년 별 과정이 존재합니다. 학변 별 과정은 level 4가 되죠.

정확한 것은 아니나, 이렇듯 정보를 단계별로 구성이 가능합니다.

+ 너무 얘기가 돌아다니네요...ㅡ.ㅡ;;;

여튼 이 포스트에서 설명하고자 하는 것은 엑셀을 통해 정보를 구성할 수 있으며, 이를 구조화할 수 있다는 것입니다.
이것은 [그룹] 혹은 [윤곽]이라는 기능이고요.

참고로 윤곽 기호가 나타남으로 인해, [행] 또는 [열]을 표시하는 공간이 넓어진다는 건데요.
이를 보이지 않도록 하는 설정도 존재합니다.

[도구] - [옵션] - [화면 표시] 탭 - [윤곽 기호]에 대한 체크를 해제하시면 됩니다.

일련의 정보들을 숨기고, 숨기기 취소하고를 편하게 하기위해서 [윤곽]을 사용하는 건데, 이를 안보이게 한다니...
조금 아이러니 하긴 하죠... 하지만 다 필요는 합니다.

일련의 묶음을 일일이 [+]와 [-]를 통해서 제어하며, 데이터를 확인하는 것이 귀찮을 수도 있습니다.

이에 대한 제어를 편하게 하는 것에는 vba 코드가 필요한데요.
vba코드에서는 Outline.Showlevels라는 프로시저(함수)를 사용합니다.
Public Sub btnGuide_Click()
    Dim DD As Shape
    Set DD = ActiveSheet.Shapes(Application.Caller)
    Dim caption As String
    caption = DD.TextFrame.Characters.Text
    call modSystem.SheetUnproject()
    If caption = "Guide 보기" Then
        DD.TextFrame.Characters.Text = "Guide 숨기기"
        ActiveSheet.Outline.ShowLevels RowLevels:=2
    Else
        DD.TextFrame.Characters.Text = "Guide 보기"
        ActiveSheet.Outline.ShowLevels RowLevels:=1
    End If
call modSystem.SheetProject()
End Sub
* ActiveSheet.Outline.ShowLevels RowLevels:=2
위의 명령어입니다. [ShowLevels] 프로시저에 [RowLevels]라는 매개변수(parameter)에 '2'로 설정을 해라. 라는 건데요.
위에서 설명한 '깊이'에 대한 level을 2로 설정한다고 생각하시면 됩니다.
위의 코드에서는 엑셀에 하나의 버튼을 두고, 그것을 통해서 level 2를 보이게 하고, 숨기고를 작업하도록 구성하였습니다.

결국 저러한 일련의 코드가 있다는 것을 설명하고 싶었는 데, 이를 위한 잡소리가 많아졌네요.ㅎㅎ;;

엑셀에서의 몰랐던 기능!!

'이름 지정'
많은 데이터를 관리할 수 있도록 도와주는 엑셀!!
엑셀은 기본적으로 하나의 SHEET에 한 종류의 데이터를 행과 열에 따라 정리하는 게 맞습니다!
하지만, 사용하다 보면 그렇게만 되지 않죠..^^;

그래서 대부분 한 SHEET를 나름의 규칙으로 다수의 영역으로 쪼개어 사용하기도 합니다.

이 때, 각 영역의 시작점 혹은 그 영역으로 이동하고 싶을 시에..

 * 스타크래프트1에서 자신이 자주 보는 지역을 지정할 수 있는 기능이 있는 것과 동일하다고 생각됩니다.
    자신의 본진, 주력 멀티, 그리고 전장...을 주로 설정하죠.ㅎㅎㅎ
    (아;;;저는 그럴 실력까진 안되고요;;;

이 '이름 지정' 기능을 하용하면 됩니다.

평소에는 그냥 현재 선택된 셀의 이름을 확인 할 수 있는 용도로 사용하거나, 아니면 그냥 대수롭지 않게 지나치던 그곳이죠!!
그곳은!!!

바로 수식 입력창 바로 왼쪽에 위치하고 있습니다.


위 캡쳐는 EXCEL 2003 이나... 아마 그 이후 버젼에서도 별반 다르진 않았던 기억이네요..^^;

이름 지정을 원하는 셀 혹은 영역(다수의 cell)을 지정한 후, 이름 지정 창에 원하는 ‘이름’을 넣으면 설정이 완료됩니다.
임의의 이름을 넣은 후 엔터!!

그리고 다른 셀에 있다가, 다시 같은 이름을 넣고, 엔터를 치면 지정한 곳으로 즉시 이동이 됩니다.ㅎㅎㅎ

지정된 이름을 삭제하는 것은 저기서 바로 되진 않습니다.

Ctrl+F2 혹은 [메인 메뉴] - [삽입] - [이름] - [정의]를 통해 관리가 가능합니다.


제가 임의로 지정한 이름들이 보이고요. 그 하단 [참조 대상]에 설정한 셀 혹은 영역이 보이네요..^^;



제가 엑셀의 이러한 기능을 포스팅한 이유는 사실 따로 있습니다.
이 기능을 통해, VBA 코드 작성시에 매우 큰 도움이 되기 때문이죠.ㅎㅎ


   
    For rowIndex = 0 To intRowCount - 1
        For fldIndex = 0 To fldCount
            Worksheets(MAIN_SHEET).Range(SHEET_TABLE).Offset(rowIndex, fldIndex - 1).value = ""
        Next
    Next

위 코드는 간단히 일정 영역을 초기화하는 코드입니다.
  - "MAIN_SHEET"와 "SHEET_TABLE"은 전역 상수로 설정한 것입니다.^^;

여기서 "SHEET_TABLE"이 해당 SHEET의 한 영역에 '이름'을 지정해둔 것이죠.
저렇듯, 코드 상에서도 WORKSHEETS의 RANGE에 이름을 넣어줌으로 해당 CELL 혹은 영역으로 바로 이동이 가능하고.
또한 OFFSET 함수를 통해 일정 구간에 대한 핸들링을 손쉽게 할 수 있습니다.

코딩하시는 개발자 분들 중에 데이터 임시 저장 파일로 EXCEL을 사용하신다면,
제가 오늘 알려드린 '이름' 기능을 써보세요.
확실히 편해집니다.^^
마치 INDEX를 통해 ARRAY를 열심히 찾아다니던 것을 KEY를 통해 바로 찾아갈 수 있는 HASHTABLE처럼요..^^

* 문제
VBA는 스크립트 언어로, 오류가 발생하면 Macro에 포함된 모든 전역 변수가 초기화 된다. (실질적으로 프로그램이 재시작하는 것으로 생각하면 된다.) 이로 인해, 프로그램이 지속될 수 있도록 전역변수들을 외부에 저장해야 할 필요성이 있다.

* 해결
변수들의 데이터를 저장할 클래스(clsInfoBackUp) 개발
변수명을 key로 하여, 데이터를 저장하며, 배열에 대해서는 배열의 차원수 및 크기를 저장할 수 있다.
특정 형식을 가진 Txt 파일로 가지고 있는 데이터를 저장할 수 있으며, 해당 파일로부터 데이터를 가져올 수 있다.

# clsInfoBackUp 클래스는 파일로 올렸습니다. 이용하기 편하게 ^^
  클래스가 800라인이 넘어가서 복사하기 힘들듯 해서요.ㅎㅎ

정보 저장 및 불러오기
오류가 발생할 수 있는 단계 직전에 아래의 코드를 삽입한다.
전역변수의 데이터를 확인한 후, 데이터가 유지되고 있으면, 저장하고, 소실되었다면 백업파일로부터 정보를 가져온다.

   
If Len(gstrPubVariable) = 0 Then
   Call modPublicDefs.LoadPubData
Else
   Call modPublicDefs.SavePubData
End If


clsInfoBackUp의 사용

사용중인 모든 전역변수를 그 이름을 key로 해서 데이터를 저장하고, 불러오는 함수를 작성한다.

   
Public Sub SavePubData() 
    Dim oBackUp As New clsInfoBackUp 
       
    Call oBackUp.AddValue("gstrLoginName", gstrLoginName) 
    Call oBackUp.AddValue("gstrUserID", gstrUserID) 
 
    oBackUp.SaveData 
    oBackUp.Clear 
    Set oBackUp = Nothing 
End Sub 
  
Public Sub LoadPubData() 
    Dim oBackUp As New clsInfoBackUp 
    Call oBackUp.LoadData 
    
    gstrLoginName = oBackUp.GetValue("gstrLoginName") 
    gstrUserSid = oBackUp.GetValue("gstrUserID") 
    oBackUp.Clear
    Set oBackUp = Nothing
End Sub


#Tip
때에 따라... 매우 많은 전역변수가 있을 것인데, 엑셀을 사용하면 편하다.
전역변수 선언을 모두 엑셀에 복사하고, 데이터를 나누어서 변수명만을 가져오고, 엑셀의 수식을 통해서 코드를 작성!!!
생각보다 짧은 시간이 소모된다.
엑셀은 정말 신적인 존재다.ㅠㅠ

# 아래 코드 중에 에러를 체크하고 핸들링하는 부분이 있는 데...
솔직히 나는 아직 에러 핸들링을 잘못하는 편이다. 아래에 포한된 부분들은 어디선가 복사를 하다보니;;

   
VERSION 1.0 CLASS
BEGIN
  MultiUse = -1  'True
END
Attribute VB_Name = "clsInfoBackUp"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
'/***********************************************************************************
' 파일명    : clsInfoBackUp
' 작성자    : 정진우
' 목적      : VBA는 script 언어로 코드 수행 중, 오류가 발생하면 모든 전역 변수가 초기화된다.
'             이로인해, 전역변수에 대한 backup이 필요하여, 이 backup은 text file로 이뤄진다.
' 사용방식  : 전역 변수가 정의된 모듈(modPublicDefs)에 SavePubData, LoadPubData를 정의해 이를 통해 사용한다.
'             LoadPubData, SavePubData 사용!
'             오류 발생 가능성이 존재하여, backup이 필요한 시점에 모든 전역 변수 정보를 AddValue 함수를 통해 저장하고,
'             SaveData 함수를 통해, file을 생성한다.
'             그리고 전역 변수를 다시 사용할 시점에 LoadData를 통해 file에 저장된 데이터를 가져오고,
'             GetValue를 통해, 전역 변수 데이터를 재할당한다.
'             본 클래스는 데이터 저장을 hashtable 형태로 하며, 그 key는 변수명으로 한다.
' 사용파일  :
' 제한사항  :
' 오류처리  :
' Remark    :
'               key와 data는 '|'를 구분자로 하여, file에 저장된다.
'                   key|data
'               array에 대한 저장은 다음의 형식으로 저장된다.
'               1. Array Info: varName(Array Dimension)|LBound-UBound{|LBound-UBound}*
'               2. Array Data: varName-index{-index}|data
'                   # {...} : 묶음
'                   # * : 0...n개 반복
'                   # AddData, GetData 등을 참조
'               Ex_
'                   # Define As
'                     dim array(,)
'                     redim array(1 to 5, 2 to 8)
'                   # Added to Table
'                     Array Info: key: array(2), data: 1-5|2-8
'                     Array Data(1,2): key: array-1-2, data: value12
'                     Array Data(3,6): key: array-3-6, data: value36
'                   # Save in file
'                     array(2)|1-5|2-8
'                     array-1-2|value12
'                     array-3-6|value36
' 이력사항
'           2012. 01/11 정진우
'               1. 생성
'/***********************************************************************************
Option Explicit

Private Const backupFilePath As String = "D:\NewSpot\Txt\"
Private Const backupFileName As String = "PublicDefsBackUp.txt"

Private Type hashtable
    key As Variant
    value As Variant
End Type

Private hashtbl() As hashtable
Private GetErrMsg As String

'/***********************************************************************************
' 함수명    : Class_Initialize
' 작성자    : 정진우
' 설명      : 생성자
' 리턴값    :
' 매개변수
' Psedo-Code
'
' Remark
' 이력사항
'           2012. 01/11 정진우
'               1. 생성
'/***********************************************************************************
Public Sub Class_Initialize()
    GetErrMsg = ""
    On Error GoTo CreateErr
        ReDim hashtbl(0)
    Exit Sub

CreateErr:
    GetErrMsg = Err.Description
End Sub

'/***********************************************************************************
' 함수명    : Class_Terminate
' 작성자    : 정진우
' 설명      : 파괴자
' 리턴값    :
' 매개변수
'           param     :
' Psedo-Code
'
' Remark
' 이력사항
'           2012. 01/11 정진우
'               1. 생성
'/***********************************************************************************
Private Sub Class_Terminate()
    'Set hashtbl = Nothing
End Sub

'/***********************************************************************************
' 함수명    : GetValue
' 작성자    : 정진우
' 설명      : 지정한 키에 대한 값을 반환한다.
' 리턴값    :
' 매개변수
'           key     : 데이터를 알아낼 key
' Psedo-Code
'           hashtable에 대한 순차검색을 수행한다.
'           key값이 동일하면, 일반 변수이며, key에 "("가 포함되면 array 변수이다.
'           Array 변수의 경우 "()"로 묶음 값이 차원의 개수이다.
' Remark
' 이력사항
'           2012. 01/11 정진우
'               1. 생성
'/***********************************************************************************
Public Function GetValue(key As Variant) As Variant
    GetErrMsg = ""
    On Error GoTo GetValueErr
        Dim found As Boolean
        Dim i As Long
        found = False
        
        For i = 1 To UBound(hashtbl)
            If hashtbl(i).key = key And IsEmpty(hashtbl(i).key) = False Then
                GetValue = hashtbl(i).value
                Exit Function
            ElseIf InStr(1, hashtbl(i).key, key & "(", vbBinaryCompare) > 0 Then
                'Array Value
                Dim startIndex As Long
                Dim endIndex As Long
                startIndex = InStr(1, hashtbl(i).key, "(")
                endIndex = InStr(startIndex, hashtbl(i).key, ")")
                Dim dimCnt As Long
                dimCnt = CLng(Mid(hashtbl(i).key, startIndex + 1, endIndex - startIndex - 1))
                Select Case dimCnt
                    Case 1
                        GetValue = GetArrayValue1(key)
                    Case 2
                        GetValue = GetArrayValue2(key)
                    Case 3
                        GetValue = GetArrayValue3(key)
                    Case 4
                        GetValue = GetArrayValue4(key)
                    Case Else
                End Select
                Exit Function
            End If
        Next i
        
        Err.Raise 9997, , "Key [" & CStr(key) & "] not found"

    Exit Function

GetValueErr:
    GetValue = ""
    GetErrMsg = Err.Description
End Function

'/***********************************************************************************
' 함수명    : GetArrayValue1
' 작성자    : 정진우
' 설명      : 1차원으로 구성된 정보를 반환한다.
' 리턴값    :
' 매개변수
'           key     :
' Psedo-Code
'
' Remark
' 이력사항
'           2012. 01/12 정진우
'               1. 생성
'/***********************************************************************************
Private Function GetArrayValue1(key As Variant) As Variant
    GetErrMsg = ""
On Error GoTo GetArrayValue1Err
    
    Dim i As Long
    Dim arrayInfo As Variant
    Const dimCnt As Integer = 1
    arrayInfo = GetValue(key & "(" & CStr(dimCnt) & ")")
    Dim lowBound(1 To dimCnt) As Long
    Dim upBound(1 To dimCnt) As Long
    
    For i = 1 To dimCnt
        arrayInfo = GetBoundary(arrayInfo, lowBound(i), upBound(i))
    Next i
    
    Dim arrayValue()
    ReDim arrayValue(lowBound(1) To upBound(1) _
                     )

    For i = 1 To dimCnt
        arrayInfo = GetBoundary(arrayInfo, lowBound(i), upBound(i))
    Next i
    
    For i = lowBound(1) To upBound(1)
        arrayValue(i) = GetValue(key & "-" & CStr(i))
    Next i
    
    GetArrayValue1 = arrayValue
    
    Exit Function

GetArrayValue1Err:
    GetArrayValue1 = Null
    GetErrMsg = Err.Description
End Function

'/***********************************************************************************
' 함수명    : GetArrayValue2
' 작성자    : 정진우
' 설명      : 2차원으로 구성된 정보를 반환한다.
' 리턴값    :
' 매개변수
'           key     :
' Psedo-Code
'
' Remark
' 이력사항
'           2012. 01/12 정진우
'               1. 생성
'/***********************************************************************************
Private Function GetArrayValue2(key As Variant) As Variant
    GetErrMsg = ""
On Error GoTo GetArrayValue2Err
    
    Dim i As Long
    Dim j As Long
    Dim arrayInfo As Variant
    Const dimCnt As Integer = 2
    arrayInfo = GetValue(key & "(" & CStr(dimCnt) & ")")
    Dim lowBound(1 To dimCnt) As Long
    Dim upBound(1 To dimCnt) As Long
    
    For i = 1 To dimCnt
        arrayInfo = GetBoundary(arrayInfo, lowBound(i), upBound(i))
    Next i
    
    Dim arrayValue()
    ReDim arrayValue(lowBound(1) To upBound(1) _
                     , lowBound(2) To upBound(2) _
                     )
    
    For i = lowBound(1) To upBound(1)
        For j = lowBound(2) To upBound(2)
            arrayValue(i, j) = GetValue(key & "-" & CStr(i) & "-" & CStr(j))
        Next j
    Next i
    
    GetArrayValue2 = arrayValue
    
    Exit Function

GetArrayValue2Err:
    GetArrayValue2 = Null
    GetErrMsg = Err.Description
End Function

'/***********************************************************************************
' 함수명    : GetArrayValue3
' 작성자    : 정진우
' 설명      : 3차원으로 구성된 정보를 반환한다.
' 리턴값    :
' 매개변수
'           key     :
' Psedo-Code
'
' Remark
' 이력사항
'           2012. 01/12 정진우
'               1. 생성
'/***********************************************************************************
Private Function GetArrayValue3(key As Variant) As Variant
    GetErrMsg = ""
On Error GoTo GetArrayValue3Err
    
    Dim i As Long
    Dim j As Long
    Dim k As Long
    Dim arrayInfo As Variant
    Const dimCnt As Integer = 3
    arrayInfo = GetValue(key & "(" & CStr(dimCnt) & ")")
    Dim lowBound(1 To dimCnt) As Long
    Dim upBound(1 To dimCnt) As Long
    
    For i = 1 To dimCnt
        arrayInfo = GetBoundary(arrayInfo, lowBound(i), upBound(i))
    Next i
    
    Dim arrayValue()
    ReDim arrayValue(lowBound(1) To upBound(1) _
                     , lowBound(2) To upBound(2) _
                     , lowBound(3) To upBound(3) _
                     )
    
    For i = lowBound(1) To upBound(1)
        For j = lowBound(2) To upBound(2)
            For k = lowBound(3) To upBound(3)
                arrayValue(i, j, k) = GetValue(key & "-" & CStr(i) & "-" & CStr(j) & "-" & CStr(k))
            Next k
        Next j
    Next i
    
    GetArrayValue3 = arrayValue
    
    Exit Function

GetArrayValue3Err:
    GetArrayValue3 = Null
    GetErrMsg = Err.Description
End Function

'/***********************************************************************************
' 함수명    : GetArrayValue4
' 작성자    : 정진우
' 설명      : 4차원으로 구성된 정보를 반환한다.
' 리턴값    :
' 매개변수
'           key     :
' Psedo-Code
'
' Remark
' 이력사항
'           2012. 01/12 정진우
'               1. 생성
'/***********************************************************************************
Private Function GetArrayValue4(key As Variant) As Variant
    GetErrMsg = ""
On Error GoTo GetArrayValue4Err
    
    Dim i As Long
    Dim j As Long
    Dim k As Long
    Dim l As Long
    Dim arrayInfo As Variant
    Const dimCnt As Integer = 4
    arrayInfo = GetValue(key & "(" & CStr(dimCnt) & ")")
    Dim lowBound(1 To dimCnt) As Long
    Dim upBound(1 To dimCnt) As Long
    
    For i = 1 To dimCnt
        arrayInfo = GetBoundary(arrayInfo, lowBound(i), upBound(i))
    Next i
    
    Dim arrayValue()
    ReDim arrayValue(lowBound(1) To upBound(1) _
                     , lowBound(2) To upBound(2) _
                     , lowBound(3) To upBound(3) _
                     , lowBound(4) To upBound(4) _
                     )
    
    For i = lowBound(1) To upBound(1)
        For j = lowBound(2) To upBound(2)
            For k = lowBound(3) To upBound(3)
                For l = lowBound(4) To upBound(4)
                    arrayValue(i, j, k) = GetValue(key & "-" & CStr(i) & "-" & CStr(j) & "-" & CStr(k))
                Next l
            Next k
        Next j
    Next i
    
    GetArrayValue4 = arrayValue
    
    Exit Function

GetArrayValue4Err:
    GetArrayValue4 = Null
    GetErrMsg = Err.Description
End Function

'/***********************************************************************************
' 함수명    : GetBoundary
' 작성자    : 정진우
' 설명      : 가장 앞에 위치한 "n-m"으로 구성된 array index 정보를 '-'를 기준으로 분할한다.
' 리턴값    : 가장 앞에 위치한 차원 정보를 제거한 info 정보
' 매개변수
'           info     : array index 정보 n1-m1{|n2-m2}
'           lowBound : 하한
'           UpLound  : 상한
' Psedo-Code
'           차원 구분자(|)를 통해 분할하고, 가장 앞에 위치한 차원 정보를 ref 매개변수에 할당하고, 남은 정보를 반환한다.
' Remark
' 이력사항
'           2012. 01/12 정진우
'               1. 생성
'/***********************************************************************************
Private Function GetBoundary(ByVal info As String, ByRef lowBound As Long, ByRef upBound As Long) As String
    Dim index As Long
    index = InStr(1, info, "-")
    Dim dimIndex As Long
    dimIndex = InStr(index, info, "|")
    
    If dimIndex = 0 Then
        lowBound = CLng(Mid(info, 1, index - 1))
        upBound = CLng(Mid(info, index + 1, Len(info)))
        GetBoundary = ""
    Else
        lowBound = CLng(Mid(info, 1, index - 1))
        upBound = CLng(Mid(info, index + 1, dimIndex - index - 1))
        GetBoundary = Mid(info, dimIndex + 1, Len(info))
    End If
    
End Function

'/***********************************************************************************
' 함수명    : AddValue
' 작성자    : 정진우
' 설명      : key를 바탕으로 변수의 데이터를 저장한다.
' 리턴값    : 변수가 포함된 인덱스, 기존에 저장된 key일 경우 -1을 반환한다.
' 매개변수
'           key     : 데이터에 대한 유일한 key
'           value   : 데이터의 값
' Psedo-Code
'
' Remark
' 이력사항
'           2012. 01/11 정진우
'               1. 생성
'/***********************************************************************************
Public Function AddValue(key As Variant, value As Variant) As Long
    GetErrMsg = ""
    On Error GoTo AddErr

        Dim idx As Long
        Dim i As Long
        Dim valueType As String
        valueType = TypeName(value)
        
        If InStr(valueType, "(") > 0 Then
            Dim cntDim As Long
            cntDim = GetDimensionCount(value)
            
            Select Case cntDim
                Case 1
                    idx = AddArrayValue1(key, value)
                Case 2
                    idx = AddArrayValue2(key, value)
                Case 3
                    idx = AddArrayValue3(key, value)
                Case 4
                    idx = AddArrayValue4(key, value)
                Case Else
                    idx = -1
            End Select
            AddValue = idx
            Exit Function
        End If
        
        idx = UBound(hashtbl) + 1
        
        Dim htVal As hashtable
        htVal.key = key
        htVal.value = IIf(IsNull(value) Or IsEmpty(value), Null, value)

        For i = 1 To UBound(hashtbl)
            If hashtbl(i).key = key Then Err.Raise 9999, , "Key [" & CStr(key) & "] is not unique"
        Next i

        ReDim Preserve hashtbl(idx)

        hashtbl(idx) = htVal
        AddValue = idx
    Exit Function

AddErr:
    AddValue = 0
    GetErrMsg = Err.Description
End Function

'/***********************************************************************************
' 함수명    : AddArrayValue1
' 작성자    : 정진우
' 설명      : 1차원으로 정의된 array의 값들을 저장한다.
' 리턴값    :
' 매개변수
'           param     :
' Psedo-Code
'
' Remark
' 이력사항
'           2012. 01/11 정진우
'               1. 생성
'/***********************************************************************************
Private Function AddArrayValue1(key As Variant, value As Variant) As Integer
    GetErrMsg = ""
    On Error GoTo AddArrayValue1Err
    
    Dim idx As Long
    Dim i As Long
    'save array info
    idx = AddValue(key & "(1)", CStr(LBound(value, 1)) & "-" & CStr(UBound(value, 1)))
    For i = LBound(value, 1) To UBound(value, 1)
        'save array data
        idx = AddValue(key & "-" & CStr(i), value(i))
    Next i
    AddArrayValue1 = idx
    Exit Function

AddArrayValue1Err:
    AddArrayValue1 = -1
    GetErrMsg = Err.Description
End Function

'/***********************************************************************************
' 함수명    : AddArrayValue2
' 작성자    : 정진우
' 설명      : 2차원으로 정의된 array의 값들을 저장한다.
' 리턴값    :
' 매개변수
'           param     :
' Psedo-Code
'
' Remark
' 이력사항
'           2012. 01/11 정진우
'               1. 생성
'/***********************************************************************************
Private Function AddArrayValue2(key As Variant, value As Variant) As Integer
    GetErrMsg = ""
    On Error GoTo AddArrayValue2Err
    
    Dim idx As Long
    Dim i As Long
    Dim j As Long
    'save array info
    idx = AddValue(key & "(2)", CStr(LBound(value, 1)) & "-" & CStr(UBound(value, 1)) _
                                & "|" & CStr(LBound(value, 2)) & "-" & CStr(UBound(value, 2)) _
                                )
    For i = LBound(value, 1) To UBound(value, 1)
        'save array data
        For j = LBound(value, 2) To UBound(value, 2)
            idx = AddValue(key & "-" & CStr(i) & "-" & CStr(j), value(i, j))
        Next j
    Next i
    AddArrayValue2 = idx
    Exit Function

AddArrayValue2Err:
    AddArrayValue2 = -1
    GetErrMsg = Err.Description
End Function

'/***********************************************************************************
' 함수명    : AddArrayValue3
' 작성자    : 정진우
' 설명      : 3차원으로 정의된 array의 값들을 저장한다.
' 리턴값    :
' 매개변수
'           param     :
' Psedo-Code
'
' Remark
' 이력사항
'           2012. 01/11 정진우
'               1. 생성
'/***********************************************************************************
Private Function AddArrayValue3(key As Variant, value As Variant) As Integer
    GetErrMsg = ""
    On Error GoTo AddArrayValue3Err
    
    Dim idx As Long
    Dim i As Long
    Dim j As Long
    Dim k As Long
    'save array info
    idx = AddValue(key & "(3)" _
        , CStr(LBound(value, 1)) & "-" & CStr(UBound(value, 1)) _
          & "|" & CStr(LBound(value, 2)) & "-" & CStr(UBound(value, 2)) _
          & "|" & CStr(LBound(value, 3)) & "-" & CStr(UBound(value, 3)) _
          )
    For i = LBound(value, 1) To UBound(value, 1)
        'save array data
        For j = LBound(value, 2) To UBound(value, 2)
            For k = LBound(value, 3) To UBound(value, 3)
                idx = AddValue(key & "-" & CStr(i) & "-" & CStr(j) & "-" & CStr(k), value(i, j, k))
            Next k
        Next j
    Next i
    AddArrayValue3 = idx
    Exit Function

AddArrayValue3Err:
    AddArrayValue3 = -1
    GetErrMsg = Err.Description
End Function

'/***********************************************************************************
' 함수명    : AddArrayValue4
' 작성자    : 정진우
' 설명      : 4차원으로 정의된 array의 값들을 저장한다.
' 리턴값    :
' 매개변수
'           param     :
' Psedo-Code
'
' Remark
' 이력사항
'           2012. 01/11 정진우
'               1. 생성
'/***********************************************************************************
Private Function AddArrayValue4(key As Variant, value As Variant) As Integer
    GetErrMsg = ""
    On Error GoTo AddArrayValue4Err
    
    Dim idx As Long
    Dim i As Long
    Dim j As Long
    Dim k As Long
    Dim l As Long
    'save array info
    idx = AddValue(key & "(3)" _
        , CStr(LBound(value, 1)) & "-" & CStr(UBound(value, 1)) _
          & "|" & CStr(LBound(value, 2)) & "-" & CStr(UBound(value, 2)) _
          & "|" & CStr(LBound(value, 3)) & "-" & CStr(UBound(value, 3)) _
          & "|" & CStr(LBound(value, 4)) & "-" & CStr(UBound(value, 4)) _
          )
    For i = LBound(value, 1) To UBound(value, 1)
        'save array data
        For j = LBound(value, 2) To UBound(value, 2)
            For k = LBound(value, 3) To UBound(value, 3)
                For l = LBound(value, 4) To UBound(value, 4)
                    idx = AddValue(key & "-" & CStr(i) & "-" & CStr(j) & "-" & CStr(k) & "-" & CStr(l), value(i, j, k, l))
                Next l
            Next k
        Next j
    Next i
    AddArrayValue4 = idx
    Exit Function

AddArrayValue4Err:
    AddArrayValue4 = -1
    GetErrMsg = Err.Description
End Function

'/***********************************************************************************
' 함수명    : SaveData
' 작성자    : 정진우
' 설명      : 사전 정의된 파일에 현재 table에 존재하는 데이터를 저장한다.
' 리턴값    :
' 매개변수
' Psedo-Code
'
' Remark
' 이력사항
'           2012. 01/11 정진우
'               1. 생성
'/***********************************************************************************
Public Sub SaveData()
    Dim FSO As FileSystemObject
    Dim FSOFile As TextStream
    Dim FilePath As String
    Dim i As Long
    
    Call modFile.CreateDirectory(backupFilePath)
    If modFile.Exists(backupFilePath & backupFileName) = True Then modFile.DeleteFile (backupFilePath & backupFileName)
    
    Set FSO = New FileSystemObject
     ' opens  file in write mode
    Set FSOFile = FSO.OpenTextFile(backupFilePath & backupFileName, 2, True)
     'loop round adding lines
    For i = 1 To UBound(hashtbl)
        If IsNull(hashtbl(i).value) Then
            FSOFile.WriteLine ((hashtbl(i).key) & "|@NULL")
        Else
            FSOFile.WriteLine (CStr(hashtbl(i).key) & "|" & CStr(hashtbl(i).value))
        End If
    Next i
    
    FSOFile.Close
    
End Sub

'/***********************************************************************************
' 함수명    : LoadData
' 작성자    : 정진우
' 설명      : 사전 정의된 파일에 저장된 값들을 가져온다.
' 리턴값    :
' 매개변수
' Psedo-Code
'
' Remark
' 이력사항
'           2012. 01/11 정진우
'               1. 생성
'/***********************************************************************************
Public Sub LoadData()
    Dim FSO As FileSystemObject
    Dim FSOFile As TextStream
    Dim FilePath As String
    Dim line As String
    Dim key As Variant
    Dim value As Variant
    Dim i As Long

On Error GoTo LoadDataErr
    
    If modFile.Exists(backupFilePath & backupFileName) = False Then
        MsgBox "BackUp 파일이 존재하지 않습니다. 시스템 관리자에게 문의하세요.", vbOKOnly
        Exit Sub
    End If
    
    Call Clear
    
    Set FSO = New FileSystemObject
     ' opens  file in write mode
    Set FSOFile = FSO.OpenTextFile(backupFilePath & backupFileName, ForReading)
    Do Until FSOFile.AtEndOfStream
        line = FSOFile.ReadLine
        i = InStr(line, "|")
        key = Mid(line, 1, i - 1)
        value = Mid(line, i + 1, Len(line))
        If value = "@NULL" Then
            Call AddValue(key, Null)
        Else
            Call AddValue(key, value)
        End If
    Loop
    
    FSOFile.Close
    
    Set FSOFile = Nothing
    Set FSO = Nothing
    
LoadDataErr:
    GetErrMsg = Err.Description
    
End Sub

'/***********************************************************************************
' 함수명    : RemoveValue
' 작성자    : 정진우
' 설명      : 요청한 key로 정의된 데이터를 삭제한다.
' 리턴값    :
' 매개변수
'           key : 제거하고자 하는 데이터의 key
' Psedo-Code
'
' Remark
' 이력사항
'           2012. 01/11 정진우
'               1. 생성
'/***********************************************************************************
Public Function RemoveValue(key As Variant) As Boolean
    GetErrMsg = ""
    On Error GoTo RemoveErr

        Dim i As Long, idx As Long
        Dim htTemp() As hashtable
        idx = 1

        For i = 1 To UBound(hashtbl)
            If InStr(1, hashtbl(i).key, key) > 0 And IsEmpty(hashtbl(i).key) = False Then
                ReDim Preserve htTemp(idx)
                htTemp(idx).key = hashtbl(i).key
                htTemp(idx).value = hashtbl(i).value
                idx = idx + 1
            End If
        Next i

        'If UBound(hashtbl) = UBound(htTemp) Then Err.Raise 9998, , "Key [" & CStr(key) & "] not found"

        hashtbl = htTemp
        RemoveValue = True
    Exit Function

RemoveErr:
    RemoveValue = False
    GetErrMsg = Err.Description
End Function

'/***********************************************************************************
' 함수명    : GetValueCount
' 작성자    : 정진우
' 설명      : 현재 저장된 값들의 개수를 반환한다.
' 리턴값    :
' 매개변수
' Psedo-Code
'
' Remark
' 이력사항
'           2012. 01/11 정진우
'               1. 생성
'/***********************************************************************************
Public Function GetValueCount() As Long
    GetErrMsg = ""
    On Error GoTo GetValueCountErr
        GetValueCount = UBound(hashtbl)
    Exit Function

GetValueCountErr:
    GetValueCount = 0
    GetErrMsg = Err.Description
End Function

'/***********************************************************************************
' 함수명    : Clear
' 작성자    : 정진우
' 설명      : 모든 데이터를 삭제한다.
' 리턴값    :
' 매개변수
' Psedo-Code
'
' Remark
' 이력사항
'           2012. 01/11 정진우
'               1. 생성
'/***********************************************************************************
Public Sub Clear()
    ReDim hashtbl(0)
End Sub

'/***********************************************************************************
' 함수명    : GetNumberOfDimensions
' 작성자    : 정진우
' 설명      : Array의 차원을 반환한다.
' 리턴값    :
' 매개변수
'           aryVariable : 차원을 알아낼 대상
' Psedo-Code
'           VBA는 Array 변수의 차원을 알아낼 수 있는 내부 함수가 없다.
'           따라서, 각 차원의 크기를 알 수 있는 함수를 통해
'           함수 수행 시 오류가 발생하면, 그 차원은 존재하지 않는다.
' Remark
' 이력사항
'           2012. 01/11 정진우
'               1. 생성
'/***********************************************************************************
Private Function GetDimensionCount(aryVariable) As Long
    'Sets up the error handler.
    On Error GoTo FinalDimension
    Dim dimNum As Long
    Dim errorCheck As Long
    'Visual Basic for Applications arrays can have up to 60000
    'dimensions; this allows for that.
    For dimNum = 1 To 60000
        'It is necessary to do something with the LBound to force it
        'to generate an error.
        errorCheck = LBound(aryVariable, dimNum)
    Next dimNum
    GetDimensionCount = -1
    Exit Function
' The error routine.
FinalDimension:
    GetDimensionCount = dimNum - 1
End Function

* 문제 발생
Textbox.Multiline = false로 지정된 textbox에 여러 줄의 문자열을 MS Word로부터 Ctrl + V(붙여 넣기)를 시도할 때 문제가 발생한다.
Ctrl + V를 한 번 누르면, 복사가 되지 않으며, 두 번째 누를 때, 특이 문자가 textbox에 들어감을 확인할 수 있다. 하지만 이에 대한 ascii 값을 확인하면, 13(carriage return), 10(line feed)으로, code 값 자체는 문제가 없다. 하지만, 이 값을 가져와 사용할 때, 특이 문자로 변환됨을 확인할 수 있다.
또한 multiline = false로 설정된 textbox에 붙여 넣고, 즉시 multiline = true인 textbox에 붙여넣을 시에 동일한 특이 문자가 복사되는 것을 확인할 수 있다. 하지만 이에 대한 ascii 값은 마이너스의 값으로 0 이하의 특이 값이다.

* 해결
Textbox의 multiline = false가 문제가 되므로, 이를 해제하였다.
그리고 해당 textbox는 한 문단으로 작성이 되어야 하므로, cr과 lf를 찾아 blank(" ")로 대체하고, 두 개 이상의 blank가 연속으로 나타난 것을 하나의 blank로 대체하는 코드를 추가하였다.
해당 소스코드를 '왜' 만들었는 지, '어떻게' 만들었는 지에 대한 정보들은 소스코드에 담겨있어야 한다.

- 주석은 각 코드에 대한 설명이 아니라, '어떠한' 문제를 풀기 위해, 무엇을 하는 지에 대해서 기술되어야 한다.
- 변경에 대한 이력 또한 기술되어야 하는 데, 변경을 유발한 '요구사항'에 대해 기술한다.
- 현재 파일(클래스, 모듈, 함수)를 사용하는 '사용파일'에 대한 이력을 남김을 통해, 현재 파일에 대한 수정 시에 함께 변경이 될 수도 있는 파일(사용파일)에 대한 정보를 확인할 수 있다.
- 생성 사유와 변경 사유에 대한 정보를 찾는 것은 쉬운 일이 아닙니다. 관련 사항을 소스코드에 주석으로 기입함을 통해 '왜' 이렇게 코딩이 되었는 지 그 즉시 파악할 수 있도록 해야합니다.

- 주석 달기는 '코딩' 전에 하는 것이 좋습니다. 코딩 전에 하는 것은 문제를 풀기 위해 사고 하는 단계로 부가적인 일이 아니라고 생각하지만, 코딩 후에 하는 것은 문제를 다 풀고난 후, 혹은 오류를 해결하고 난 후의 일이기 때문에, 또다른 일이 되어버리거든요.

* "index 값을 1증가 시킨다.", "임시 변수에 데이터를 백업한다."처럼 코드를 설명하기 위한 주석은 프로그래밍 언어를 배우는 학생에게나 필요한 것 입니다. 코드의 syntax를 모르는 학생이 이해할 수 잇도록 하는 것일 뿐, syntax를 아는 사람에겐 아무 의미가 없습니다.

파일 주석

  
'/******************************************************************************
' 파일명    : 파일명을 입력
' 작성자    : 작성자 이름을 입력
' 목적      : 파일의 목적을 입력
' 사용방식  : 본 파일을 사용하는 방식을 구체적으로 입력
' 사용파일  : 본 파일을 사용하는 파일의 이름을 입력
' 제한사항  : 본 파일을 사용하는 데 필요한 사항을 입력
' 오류처리  : 본 파일에서 처리한 오류에 대해 입력
' 이력사항
'              YYYY. MM/DD 수정자
'               1. 수정 사유: method_name {, method_name}
'/******************************************************************************


함수 주석


   
'/******************************************************************************
' 함수명    : 함수명을 입력
' 작성자    : 함수 작성자 이름을 입력
' 설명      : 함수 목적에 대한 설명
' 리턴값    : 함수의 반환값을 입력
' 매개변수
'           매개변수명     : 변수 정의를 입력
' Psedo-Code
'           함수 구현에 대한 수도코드를 입력
' Remark
'           함수에 대한 특이 사항을 입력
' 이력사항
'           YYYY. MM/DD 수정자: 변경 날짜 및 수정자의 이름을 입력
'               1. 수정 사유
'/******************************************************************************


파일 내부의 이력 사항은 [파일에 대한 주석], [함수에 대한 주석], [함수 내부의 수정 내용]에 대해 일련의 링크로 볼 수 있다.
[파일 주석-method_name] - [함수 주석-날짜] - [함수 내부 날짜]로 이력사항을 확인할 수 있다.

함수 내부

   
‘YYYY. MM/DD 수정 관련 이력


저는 하나의 함수를 작성하기에 앞서,
주석을 통해 함수 내부에서 처리해야 할 내용과 어떻게 처리할 것인지에 대해 "우선적"으로 기술합니다.

1. 함수명과 리턴값, 매개변수 작성: 함수 뼈대를 작성합니다.
2. 주석 생성: 위의 주석을 그대로 Ctrl + C & Ctrl + V 하고, 설명 및 리턴값을 기술합니다.
3. 주석 내부에 Psedo-Code에 함수에서 처리하고자 하는 문제를 푸는 방식을 간단한 순서도 형식으로 기술합니다.
4. 작성한 Psedo-Code의 내용을 함수 내부로 복사합니다.
5. Psedo-Code의 각 line에 해당 하는 코드를 작성합니다.

물론 Test Driven Development로 수행하고자 한다면, 2번과 3번 사이에 관련 테스트 코드를 작성해서 그 즉시 테스트를 수행할 수 있도록 하는 것이 좋습니다.

위와 같은 순서로 코딩을 하게 된다면, 문제와 알고리즘에 대한 분석이 끝난 후가 되기 때문에, 코딩 중에 발생할 수 있는 문제들에 대해 미리 생각하고 대처할 수 있습니다.
그것도 무려 자연어(한국어, 영어)로 기술된 것을 보면서요.

사용하는 프로그래밍 언어에 따라 조금씩 다르지만, C 혹은 C++과 같이 Pointer를 사용하는 언어의 경우, 그 소스코드를 보고 오류를 찾아내고, 분석해서, 디버깅하는 것은 조금 어렵습니다.
코드를 따라가다보면, 헷갈리기 쉽상이죠.

자연어로 된 것을 풀어나가는 게 더욱 쉽다는 것은 당연한 것!!!

올바른 주석을 달아 쉽게 코딩합시다.^^

'배움 > SE' 카테고리의 다른 글

소스코드 주석달기  (1) 2012.02.20