2010년 11월 5일 금요일

PowerBuilder DB로 부터 새로운 버전의 파일을 다운로드

Oracle DB의 LONGRAW 필드에 binary EXE 또는 Image 등을 업로드 해 놓고 Client의 Program 실행시에
버전을 검사하여 하위버전인 경우 다운로드 하도록 하는 프로그램.
업무구분에 따라 경로가 고정되어 있었으나 경로의 복잡성이 추가되어
파일이름에 경로를 붙여 사용하도록 협의되어 일부 수정되었다.

SetPointer(HourGlass!)
/* Transaction Connection */
File_Tran = Create Transaction
File_Tran.dbms       = dbms
File_Tran.logid      = userid
File_Tran.logpass    = passwd
File_Tran.servername = servername

Connect Using File_Tran;
If File_Tran.sqlcode <> 0  Then
    MessageBox ("확인",' 데이터베이스 연결 실패입니다.')
    Halt Close
    Return
End If


/* 선언부 */
String   FileName,   Version_PC,  FileStyle
String   RootPath,   FullPath,    EtcPath, FilePath, IniPath, ExePath
String   ConnectParm
Boolean  lb_Check = False

Integer  li_I, FP ,  Loops,       li_Complete,    Version_SR
Long     FLen = 0,   bytes_Read = 0,  Start_Pos = 0, Next_Pos = 0
Blob     ImageData,  Blob_Chunk


/* PC 에서 최초 실행시 각 사용자별  디렉토리 생성 */
RootPath = 'c:\program'                 // 기본 디렉토리
FullPath = RootPath + '\' + gs_UserID   //------ 실행 화일관리
EtcPath  = FullPath + '\' + 'etc'       //------ 기타화일 관리

/* 화일 저장 디렉토리 생성 */
If FileExists(RootPath) Then
    If FileExists(FullPath) Then
    If FileExists(EtcPath) = False Then
            CreateDirectoryA(EtcPath,0) 
        End If
    Else
        CreateDirectoryA(FullPath,0) 
        CreateDirectoryA(EtcPath,0)     
    End If
Else
    CreateDirectoryA(RootPath,0)
    CreateDirectoryA(FullPath,0) 
    CreateDirectoryA(EtcPath,0)       
End If  

/* 각 단위 업무 수정사항  조회 */
DECLARE Cur_File CURSOR FOR
    SELECT VER_FILENAME,         VER_VERSION,    VER_EXT_STYLE
    FROM CLSM_VER11_PROGRAM
    WHERE VER_UPMUCODE = :gs_JobGubun OR
        VER_UPMUCODE = 'S'
    ORDER BY VER_FILENAME   ASC  using File_Tran;

OPEN Cur_File;
FETCH Cur_File INTO :FileName, :Version_SR,  :FileStyle;

/* 화일 버전 체크 위항 ini 화일 체크하고 생성 */
IniPath = FullPath + '\' + gs_UserID + '.ini'
wf_Write_ini(IniPath, gs_UserID)


// 2010. 11. 6 수정
// dwis 추가로 Filename에 경로를 붙여 처리하도록 수정
//-----------------------------------------------------------------------------------------------------

String ls_full_name = ""
String ls_split_name = ""
String ls_target_path = ""
integer li_root_pos

DO WHILE File_Tran.SQLCode = 0 
    //-----------------------------------------------------------------------------------------------------
    // 저장할 경로가 존재하는지 검사 : 없으면 새로 만듦
    //-----------------------------------------------------------------------------------------------------
 

    ls_full_name = FileName 
    // 먼저 파일명을 제외한 패스가 존재하는지 부터 점검 
    ls_target_path = midA(ls_full_name, 1, Len(ls_full_name) - Pos(Reverse(ls_full_name), "\")) 
    ls_split_name = ""
    // 없으면 아래를 실행
    If Not FileExists(ls_target_path) Then
        DO while(true)
            li_root_pos = pos(ls_full_name, "\")
   

            // 마지막 자료는(\가 없음) Skip << 파일이름
            IF li_root_pos < 1 THEN
                EXIT
            END IF
            If ls_split_name = "" then
                ls_split_name += midA(ls_full_name, 1, li_root_pos - 1)
            else
                ls_split_name += "\" + midA(ls_full_name, 1, li_root_pos - 1)
            end if
            ls_full_name = midA(ls_full_name, li_root_pos + 1)

            // 드라이브 문자열만 들어올 경우 Skip (ex: c:, d: << \ 기호가 없음)

            If pos(ls_split_name, "\") > 0 Then   
                // 경로가 없을 경우 생성
                If Not FileExists(ls_split_name) Then
                    CreateDirectoryA(ls_split_name,0)
                End If
            End If
        LOOP
    End If

    //-----------------------------------------------------------------------------------------------------
    Version_PC = ProfileString(IniPath, FileName, 'FileVersion', "X")

    If (Version_SR <> Integer(Version_PC)) OR Version_PC = 'X' Then
        If lb_Check = False Then
            // 다운 받고 있을때의 Animation // 

            This.Title = '화일 내려받는 중 '        
            DelAnim()
            Trigger Event ue_animation()
  
             lb_Check = True
        End If     
 
        uo_1.uf_setvisible(0)
        st_filename.Text = FileName
      
        SELECTBLOB VER_FILESOURCE
        INTO :ImageData
        FROM CLSM_VER11_PROGRAM
        WHERE VER_FILENAME = :FileName    AND
             (VER_UPMUCODE= :gs_jobgubun OR
            VER_UPMUCODE= 'S' )
        using File_Tran ;

        IF File_Tran.Sqlcode <> 0  THEN
        DisConnect Using File_Tran;
        DelAnim()
        Halt Close
        Return
    End If 

    //-----------------------------------------------------------------------------------------------------
    // 파일 이름에 \이 포함된경우 이름 그대로 경로처리 : 추가

    If Pos(FileName, "\") > 0  Then
        FilePath = FileName
    Else

        // 기존 처리 방식
        /* 실행화일과 PBD 이외의 화일은 BMP 디렉토리에 관리 */

        If Upper(FileStyle) = 'EXE' OR Upper(FileStyle) = 'PBD' Then
            FilePath = FullPath + '\' + FileName               
        ElseIf Upper(FileStyle) = 'BMP' Then
            FilePath = RootPath + '\install\bmp\' + FileName
        ElseIf Upper(FileStyle) = 'DLL' Then 
            FilePath = RootPath + '\install\lib\' + FileName
        Else
            FilePath = EtcPath + '\' + FileName
        End If
    End If
    //----------------------------------------------------------------------------------------------------- 
    FP = FileOpen(FilePath, StreamMode!, Write!,LockWrite!, replace!)  
    ///// **** 화일 변수 책정 초기화 **** ///////

    Next_Pos = 1;   Loops = 0;   FLen = 0
    IF FP <> 0 then
        Flen = Len(ImageData)
        st_size.Text = String(FLen,'#,###,###')
        If FLen > 32765 Then
            If Mod(FLen,32765) = 0 Then
                Loops = FLen/32765
            Else
                Loops = (FLen/32765) + 1
            End If
        Else
            Loops = 1
        End If

        If Loops = 1 Then
            Bytes_Read = FileWrite(FP,ImageData)
            uo_1.uf_setvisible(100)  
        Else
            For li_I = 1 To Loops
                    li_Complete = ( (32765 * li_I ) / Len(ImageData)) * 100
                    uo_1.uf_setvisible(li_Complete)
                    If li_I = Loops Then
                        Blob_Chunk = BlobMid(ImageData,Next_Pos)
                    Else
                        Blob_Chunk = BlobMid(ImageData,Next_Pos,32765)
                    End If
                    Bytes_Read = FileWrite(FP, Blob_Chunk)
                    Next_Pos   = Next_Pos + Bytes_Read
                Next 
            End If
         
            FileClose(FP)
 
            ///// 차후 화일 다운 받기 위한 초기화 화일 /////

            SetProfileString(IniPath, FileName, 'FileVersion', String(Version_SR)) 
        End If
    End If

    FileName = '';    Version_PC = '';

    FETCH Cur_File INTO :FileName, :Version_SR,  :FileStyle;
LOOP

CLOSE Cur_File;
/* 실행 화일 넘겨질 변수 설정 */
ConnectParm = gs_UserID + '/' + gs_UserPassWD + '/' + dbms + '/' + servername +&
              '/' + gs_Jobgubun + '/' + gs_Sabun + '/' + gs_Passwd + '/' + '' + '/'

ExePath = FullPath + '\' + gs_UserID + '.exe '

If FileExists(ExePath) = False Then
    DisConnect Using File_Tran;
    MessageBox("확인", '당 업무 해당 실행화일이 없습니다. 프로그램을 종료하겠습니다.'&
                       ,StopSign!)
    Halt Close
    Return
End If  

Close(This)
Close(w_jobbmp_display)

//각 단위 업무 화일  실행 //
Run(ExePath + ConnectParm)



ASP.NET에서 다른컴퓨터의 폴더 Access

web.config의 <system.web> 내부에 다음 항목 추가

      <identity impersonate="true" userName="사용자계정" password="암호" />

폴더를 Access할때 위 계정정보를 사용하여 Access함.
당연히, 해당 컴퓨터에 사용자 정보를 만들어 줘야함

OCR 인식 테스트 : MS Officce Document Imaging : 배율확대에 의한 인식율

MS Office Document Imaging의 OCR 인식 기능을 사용하여 숫자만 가득한 이미지를 테스트 해 보았다.
인식이 잘 되는 경우도 있고 안되는 경우도 있어서 이미지를 단계별로 확대해 가며 정확하게 읽어지는지 검사했다.
주로 1.4배~1.7배 사이에서 인식이 잘 되는것 같긴 한데..
이미지에 따라 인식율이 다르게 나온다.

더 나은 OCR 라이브러리가 필요할듯...

1x    115440 4,285 4,260 4.320 4,260 4 290 4,930 3,650 3,660 15 4.. 260 1 090
1.1x  115440 4285 4,260 4,320 4,260 4, 290 4,930 3650 3,660 15 4, 261) 1 .fl
1.2x  115440 4,285 4,260 4,320 4260 4,290 4,930 3,650 3,660 15 4,260 1 .090
1.3x  115440 4,285 4,260 4,320 4,260 4,290 4,930 3,650 3,660 15 I L LJJ L090
1.4x  115440 4.285 4.260 4.320 4.260 4.2% 4.930 3.650 3.660 15 4.260 1.090
1.5x  115440 4,285 4,260 4,320 4,260 4,290 4,930 3,650 3,660 15 4,260 1090
1.5x  115440 4,285 4,260 4,320 4,260 4,290 4,930 3,650 3,660 15 4,260 1090  24bit
1.6x  115440 4,285 4,260 4,320 4,260 4,290 4,930 3,650 3,660 15 4,260 1,090 *****
1.7x  115440 4,285 4,260 4,320 4,260 4,290 4,930 3,650 3,660 15 4,260 1,090
1.8x  115440 4,285 4,260 4,320 4,260 4,290 4,930 3,650 3,660 15 4,260 L090
1.9x  115440 4,285 4,260 4,320 4,260 4,290 4,930 3,650 3,660 15 4,260 1,090
2x    115440 4,285 4,260 4,320 4,260 4,290 4,930 3,650 I_I, ? 15 4,260 1,090
3x    p _ C) N) 0, CDN)N)C)N) CD 0, 0, C) CD 0, N) 0, C) 0, (1 p p (T

* 정규식
[0-9]{5,6}\s+[\,\.0-9]{2,10}\s+[\,\.0-9]{2,10}\s+[\,\.0-9]{2,10}\s+[\,\.0-9]{2,10}\s+[\,\.0-9]{2,10}\s+[\,\.0-9]{2,10}\s+[\,\.0-9]{2,10}\s+[\,\.0-9]{2,10}\s+[\,\.0-9]{2,10}\s+[\,\.0-9]{2,10}\s+[\,\.0-9]{2,10}

C#에서 MD5 암호화 사용

public string GetMD5Hash(string input)
{
System.Security.Cryptography.MD5CryptoServiceProvider x = new System.Security.Cryptography.MD5CryptoServiceProvider();
byte[] bs = System.Text.Encoding.UTF8.GetBytes(input);
bs = x.ComputeHash(bs);
System.Text.StringBuilder s = new System.Text.StringBuilder();
foreach (byte b in bs)
{
s.Append(b.ToString("x2").ToLower());
}
string password = s.ToString();
return password;
}

Rijndael(AES) 암/복호화 코드(C#)

AES 미국 정부에서 민감한 정보들을 암호화하는 사용되는 표준 /복호화 알고리즘입니다. 현재 업계 표준이고, 아직까지는 알려진 약점이 없는 가장 안전한 /복호화 알고리즘입니다. 최근에 일부 SI 프로젝트에서는 방식을 것을 요구하기도 합니다.

1. 암호화

private static string EncryptString(string InputText, string Password)
{
// Rihndael class를 선언하고, 초기화 합니다
RijndaelManaged RijndaelCipher = new RijndaelManaged();

// 입력받은 문자열을 바이트 배열로 변환
byte[] PlainText = System.Text.Encoding.Unicode.GetBytes(InputText);

// 딕셔너리 공격을 대비해서 키를 더 풀기 어렵게 만들기 위해서
// Salt를 사용합니다.
byte[] Salt = Encoding.ASCII.GetBytes(Password.Length.ToString());

// PasswordDeriveBytes 클래스를 사용해서 SecretKey를 얻습니다.
PasswordDeriveBytes SecretKey = new PasswordDeriveBytes(Password, Salt);

// Create a encryptor from the existing SecretKey bytes.
// encryptor 객체를 SecretKey로부터 만듭니다.
// Secret Key에는 32바이트
// (Rijndael의 디폴트인 256bit가 바로 32바이트입니다)를 사용하고,
// Initialization Vector로 16바이트
// (역시 디폴트인 128비트가 바로 16바이트입니다)를 사용합니다
ICryptoTransform Encryptor = RijndaelCipher.CreateEncryptor(SecretKey.GetBytes(32), SecretKey.GetBytes(16));

// 메모리스트림 객체를 선언,초기화 
MemoryStream memoryStream = new MemoryStream(); 

// CryptoStream객체를 암호화된 데이터를 쓰기 위한 용도로 선언
CryptoStream cryptoStream = new CryptoStream(memoryStream, Encryptor, CryptoStreamMode.Write);
                 
// 암호화 프로세스가 진행됩니다.
cryptoStream.Write(PlainText, 0, PlainText.Length);
                 
// 암호화 종료
cryptoStream.FlushFinalBlock();

// 암호화된 데이터를 바이트 배열로 담습니다.
byte[] CipherBytes = memoryStream.ToArray();



// 스트림 해제
memoryStream.Close();
cryptoStream.Close();
       
// 암호화된 데이터를 Base64 인코딩된 문자열로 변환합니다.
string EncryptedData = Convert.ToBase64String(CipherBytes);

// 최종 결과를 리턴
return EncryptedData;
}

2. 복호화

private static string DecryptString(string InputText, string Password)
{
RijndaelManaged  RijndaelCipher = new RijndaelManaged();

byte[] EncryptedData = Convert.FromBase64String(InputText);
byte[] Salt = Encoding.ASCII.GetBytes(Password.Length.ToString());
       
PasswordDeriveBytes SecretKey = new PasswordDeriveBytes(Password, Salt);
       
// Decryptor 객체를 만듭니다.
ICryptoTransform Decryptor = RijndaelCipher.CreateDecryptor(SecretKey.GetBytes(32), SecretKey.GetBytes(16));

MemoryStream  memoryStream = new MemoryStream(EncryptedData);
           
// 데이터 읽기(복호화이므로) 용도로 cryptoStream객체를 선언, 초기화
CryptoStream  cryptoStream = new CryptoStream(memoryStream, Decryptor, CryptoStreamMode.Read);

// 복호화된 데이터를 담을 바이트 배열을 선언합니다.
// 길이는 알 수 없지만, 일단 복호화되기 전의 데이터의 길이보다는
// 길지 않을 것이기 때문에 그 길이로 선언합니다
byte[] PlainText = new byte[EncryptedData.Length];
       
// 복호화 시작
int DecryptedCount = cryptoStream.Read(PlainText, 0, PlainText.Length);
               
memoryStream.Close();
cryptoStream.Close();
       
// 복호화된 데이터를 문자열로 바꿉니다.
string DecryptedData = Encoding.Unicode.GetString(PlainText, 0, DecryptedCount);
       
// 최종 결과 리턴
return DecryptedData;
}