2015년 2월 27일 금요일

VB6, Win7에서 Microsort window common controls 6.0 컨트롤 등록이 안될때

예전 소스를 열어보니.


라고... 뜬다.

Win7 에서 VB6로 개발 하다보면 자주 보는일이니... 뭐...


대체 뭐가 맘에 안들어서 그러는지, log 를 본다.


흠....

저건 Microsort window common controls 6.0 이 없어서 나는 오류다.


"프로젝트 > 구성요소..." 로 가서...


"Microsort window common controls 6.0" 를 체크해 구성요소를 등록해 준다.


... 쉣...



어라?... "C:\Windows\SysWOW64" 에 보니 파일이 있는데?

...

원래는 정상적으로 등록되어야 하나, Window7 에선 그냥 등록이 안된다.
그러니...

 "C:\Windows\SysWOW64" 로 이동해서...


수동으로 등록을 해주자...

regsvr32 mscomctl.ocx
regtlib msdatsrc.tlb

... 라고 치면 된다.
가끔 "regsvr32 mscomctl.ocx" 만 치고 안된다고 하는 사람이 있는데, "regtlib msdatsrc.tlb" 이거 까지 다 쳐 줘야 된다.

그러면...


딱... 등록이 된다.



2015년 2월 26일 목요일

Sencha Touch 1.x 에서 "WebKitPoint is not defined" 에러가 난다.

와... 세상이 개발자가 살기 너무 힘든거 같다...

예전에 만든 프로그램이 갑자기 페이지가 안나와서 문제를 찾아 보니, 결국 센챠터치 문제였다.

센챠터치 1.1 로 만든 하이브리드 앱이었는데, 페이지 하나로 Pc, 안드로이드, 아이폰 까지 모두 쓸수 있게 만들자... 라는 컨셉으로 만든 것.

증상은 그냥 말그대로 페이지에 상단에 타이틀 부분만 나오고 아래로 아무것도 안나옴.
문제는 센차터치로 만든 페이지가 폰에서는 잘나오는데, Pc 에서만 안나옴.

개발자 콘솔로 오류를 찾아보니,  "WebKitPoint is not defined" 가 잔뜩 떠 있는것을 발견.
아마 이게 문제인듯...



인터넷을 뒤져보니...
"Google Chrome" 을 업데이트 한 이후로 동일한 증상이 생긴다는 얘기를 찾았다.

포럼에 보니 동일한 질문을 올린 글에 달린 답변이, 1.x 버젼은 더이상 지원하지 않는다고...
이걸 어쩜? -_-;

다행이 다른 사람이 해결책을 올려놓은 것이 있어 해결 했다.
http://stackoverflow.com/questions/27040297/uncaught-referenceerror-webkitpoint-is-not-defined

문제가 되는 것은 이부분...


저기 센차터치 라이브러리 파일에서...



저~~~기 있는 "WebKitPoint()" 라는 것이 크롬이 없데이트 되면서 없어져 버린게 문제.
근본적인 해결책은 센챠터치 자체를 최신 버젼으로 업데이트 해주는게 최선이겠으나...
이걸 괜히 건드렸다가 문제가 얼마나 더 커질지 모르니 함부로 건드릴 수가 없다.

암튼, 위의 링크에 있듯이 이 부분만 살짝 해결 하는 방법은...



이렇게 바꿔주면 일단 해결된다.

var rect = this.dom.getBoundingClientRect();
return [rect.left, rect.top];


아... 정말 힘들다...
되던건 좀 그냥 되게 놔주지 좀...





2015년 2월 25일 수요일

VB6 반복문 수행시 "응답없음" 상태가 되지 않으려면 DoEvents 를 사용한다.

지금하고 있는 프로젝트의 VB 프로그램에서는 특정 폴더에 쌓인 파일들을 서버로 일괄 전송하는 부분이 있다.

여기에 쌓이는 파일의 갯수 및 용량이 제법 만만찮고, 이것을 반복문을 사용해 처리하다 보니, 완료되는데 몇분에서 심하면 몇십분이 걸리기도 한다.
문제는 이렇게 전송되는 도중에는 프로그램이 먹통(외부 입력을 받아들이지 않는상태) 가 되어 버려서, 사용자가 보기에는 프로그램이 다운되어 버린것처럼 보이는데다가, 괜히 사용자가 마우스로 몇번 클릭이라도 해버리면 "응답없음" 메시지창이 떠버린다.


물론 그냥 내버려 두면 알아서 작업완료한뒤 정상으로 돌아오지만, 사용자가 "프로그램 닫기" 버튼이라도 눌러 버리면, 정말 답이 없다.
요즘의 프로그램 같으면 쓰레드로 처리하면 간단할 문제지만, VB6 에선 쓰레드로 처리할 수가 없으니...

이럴때 완벽하지는 않지만, 어느정도는 보완가능한 기능이 "DoEvents" 다.

'--작업디렉토리에 쌓인 파일 체크
    strDir = Dir(Config.WORKFOLDER & "\server\*." & Config.EXTENSION, vbNormal)

    While Not strDir = ""
        DoEvents

        '-- 파일 전송
        File_Copy(Config.WORKFOLDER & strDir, trDir & strDir)
        strDir = Dir
    Wend

대충 이런 식으로 쓰는데, 이렇게 하면 왠만해서는 "응답없음" 메시지 보기가 어렵다.
뭔가 대단해 보이지만, 사실 별게 아닌게, "응답없음" 메시지는 프로그램이 작업하는데 바빠서 사용자가 프로그램에게 보낸 메시지를 제때 처리하지 못해 발생하는 것.
그러므로, 반복문 안에 "DoEvents" 를 써놓아 한번 작업이 끝날때 마다 메시지 큐를 처리해서 "응답없음" 상태가 되는것을 방지하는 것이다.

문제는 "DoEvents" 는 진짜로 단순히 메시지큐만 정리할 뿐, 다른 일은 아무것도 하지 않는다는 것. 즉, 다른 액션을 취하게 할 수는 없다는 것이다. 말하자면 어디까지나 오류방지 차원이지 멀티 태스킹의 용도는 전혀 아님.
그렇다보니, 작은 파일 여러개를 처리하는 경우라면 문제 없지만, 아주 큰 파일 1개를 옮기는 작업 같은것에선 "응답없음" 상태가 되는것을 막을수 없다.
"DoEvents" 는 뭔가 특별한 옵션 같은게 아니라, 그저 메시지 정리 명령어에 불과 하니까... 아... 좀 아쉽다... 뭐, VB6 에 너무 큰기대는 무린가...

하하... 만족할 정도는 아니지만, 이게 어디야...

2015년 2월 23일 월요일

C# Winfrom 실행시 바로 트레이 아이콘으로 가게 하기

프로그램을 짜다 보면 사용자의 눈에 안띄게 프로그램해야 할 경우도 있다.

이런경우 그냥 실행시 프로그램의 visible 를 False 로 하고, 트레이 아이콘을 등록해 주면 된다.


간단하게 폼 하나를 추가하고.


notifyIcon 컨트롤을 추가해 준다.


보여줄 아이콘이 지정되어 있지 않으면 notifyIcon 을 등록해도 소용이 없으므로, 적당한 아이콘을 찾아 지정해 준다.


제대로 지정했으면 지정한 아이콘이 보일 것이다.



그리고, ContextMenuStip 를 하나 추가해 준다.
물론 없어도 실행하는데는 별 상관이 없지만, 이게 없으면 정상적인 방법으로는 실행시킨 프로그램을 종료할 방법이 없어지므로 추가해 준다.


실행 폼이 여러개라면 맨처음에 실행될 frmStart 를 시작 폼으로 기록해 둔다.


시작 폼에 위와 같이 소스를 작성한다.

public frmStarter()
        {
            InitializeComponent();

            this.WindowState = FormWindowState.Minimized;
            this.ShowInTaskbar = false;
            this.Visible = false;
            this.notifyIcon1.Visible = true;
            notifyIcon1.ContextMenuStrip = contextMenuStrip1;
        }

        private void 종료ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

이렇게 하고 실행하면...


아무런 액션이 일어나지 않지만, 트레이에 자세히 보면 새로운 아이콘이 등록된것이 보인다.
당연한 말이지만, 트레이아이콘 마져 등록하지 않으면, 아무런 표시없이 실행되게 할 수도 있다. (물론 프로세스 목록에선 나타나겠지만...)


ContextMenuStip 가 등록되어 있으므로 마우스 오른쪽 버튼을 클릭시 팝업 메뉴가 나타나고 "종료"를 선택시 프로그램이 종료된다.



2015년 2월 16일 월요일

VB6.0 에서 Config.ini 파일 컨트롤 하기.

프로그래밍할때 환경 설정 파일을 다루는 방법은 여러가지가 있지만, 역기 그 중에 가장 간단한 것은 ini 파일을 만들어서 텍스트로 관리하는 것이다.

VB 는 간단하게 API 를 제공하는데...


그냥 간단히, "WritePrivateProfileString Lib kernel32" 를 참조하고.
WritePrivateProfileString() 로 쓰면된다.

저렇게 만들고 버튼을 클릭해 실행해 보면...


위에서 지정한 AppName 인 "Config" 가 [Config] 라는 구분자로 설정값을 등록해 놓았음을 볼 수있다.

만약 AppName 인 "Config" 가 아닌 다른 값을 지정하면 같은 파일 안에서 서로다른 설정값 그룹을 만들수도 있다.


이렇게 괄호 [] 로 구분된 서로 다른 설정값 그룹을 생성해 관리 할 수도 있다.
이 말은 같은 ini 파일에 있다고 해도 설정값 그룹이 다른면 다른 그룹의 값은 읽을 수 없다는 얘기 이므로 설정 값을 읽거나 쓸때 지정된 그룹에 주의 해야 한다.

그리고 위의 예제보다는 일반적으로 공통 모듈을 만들어 쓰는 것이 일반적이다.

Private Declare Function GetPrivateProfileString Lib "kernel32" Alias "GetPrivateProfileStringA" _
        (ByVal lpApplicationName As String, ByVal lpKeyName As Any, ByVal lpDefault As String, _
        ByVal lpReturnedString As String, ByVal nSize As Long, ByVal lpFileName As String) As Long

Private Declare Function WritePrivateProfileString Lib "kernel32" Alias "WritePrivateProfileStringA" _
        (ByVal lpApplicationName As String, ByVal lpKeyName As Any, ByVal lpString As Any, _
        ByVal lpFileName As String) As Long

Public Function gINIRead(sSession As String, sKey As String, sINIFile As String, Optional ByVal sDefault As String = "") As String
    Dim lngRet      As Long
    Dim strValue    As String * 1024

    lngRet = GetPrivateProfileString(sSession, sKey, sDefault, strValue, 1024, App.path & "\" & sINIFile)
    gINIRead = Left(strValue, InStr(strValue, Chr(0)) - 1)

End Function

Public Function gINIWrite(sSession As String, sKey As String, sData As String, sFileDir As String, sINIFile As String) As Boolean
    Dim lngRet As Long
    Dim sFilePath As String
    
    If sFileDir = "" Then
        sFilePath = App.path & "\" & sINIFile
    Else
        sFilePath = sFileDir & "\" & sINIFile
    End If
    
    lngRet = WritePrivateProfileString(sSession, sKey, sData, sFilePath)
    
    If lngRet = 0 Then
        gINIWrite = True
    Else
        gINIWrite = False
    End If
End Function


이렇게 모듈을 만들어 놓으면...

    strPort = gINIRead(AppName, "Port", "Config.INI", "0")

    Call gINIWrite("TIME", AppName, sTime, sDir, "Config.INI")

이렇게 간략하게 읽고 쓸수가 있다.



VB6.0 에서 사용자 정의 컨트롤 (User Control) 사용하기.

VB6 에서 사용자 컨트롤을 사용하기 위해서는 일단 프로젝트를 하나 만들어야 한다.
바로 사용자 컨트롤을 만들수 는 없다.
단, 특정 프로젝트에서 만든 사용자 컨트롤은 다른 프로젝트에서 불러와 사용할 수는 있다.

일단 프로젝트를 하나 만들고...
사용자 컨트롤을 추가한다.



그러면 프로젝트에 사용자 컨트롤이 추가 되고...


일반적인 윈폼 만들듯이 사용자 컨트롤을 만들수 있다.


이렇게 사용자 컨트롤을 추가했으면, 왼쪽의 도구 탭에 사용자컨트롤 아이콘이 추가된다.
이걸 끌어다 쓰면 된다.



단, 주의 할점은 사용자 정의 컨트롤 작업창이 열려 있을 경우 삽입한 폼에서 컨트롤 추가/삭제/수정 등이 안된다.


암튼 이렇게 넣으면 바로 실행해서 쓸수 있다.
문제는 이 사용자 컨트롤에 어떤 값을 넘겨줄때가 문제 인데... 이럴때는...


사용자 컨트롤에서 "Property Let" 으로 속성을 지정해 주고...


사용폼에서 그 사용자 컨트롤의 속성을 특정값으로 지정해 주면 된다.
이렇게 하면...



사용자 폼에서 사용자 컨트롤 폼의 값을 컨트롤 할 수 있다.







2015년 2월 13일 금요일

VisualStudio 2013 Express 에서 ClickOnce(클릭원스) 배포하기

보통 VisualStuio Express 버젼은 설치파일을 만들수 없다고 알려져 있는데, 사실 안되는건 아니다.
엄밀히 얘기하면, Express 에 설치본 만들기 기능이 없는것은 맞지만, 사실 MS 에서 로컬 배포기능 자체를 만들지 않고 있다.
Express 가 아닌 정식 버젼에서도 자체 설치파일 만들기 기능은 제공하지 않고 있으며, InstallShield Limited 판을 제공하고 그걸 통해서 설치파일을 만들게 하고 있다.
다시말해 정식판과 Express 의 차이라고는 "InstallShield Limited" 판을 제공하고 있느냐 아니냐 하는 정도의 차이가 있을 뿐.

그게 어느정도 이해가 되기도 하는게, 어차피 만들어 놔봐야 다른 배포툴을 이용하는게 현실이니 궂이 만들생각이 없을 만도 하다.

암튼, MS 에서는 이제 로컬 배포 보다는 웹배포를 밀기로 작정한듯.
그래서 웹배포 방식 (ClickOnce) 은 Express 에서도 가능하다.
의외로 이걸 잘 모르는 사람이 많은듯하다.

쓰는 방법은 어차피 이전과 같은데.

프로그램 속성에서...


게시탭의 내용을 등록하면된다.


폴더 위치는 웹접근이 가능한 위치를 지정하고, 아래에는 접근 가능한 웹URL 을 적으면 된다.
배포할 폴더 위치는 일반적으로 웹배포를 할때는 개발 PC 가 아닌 다른 서버에서 배포를 하니 주로 FTP를 쓰지만, 로컬 경로에 배포판을 만드는것도 가능하다.
이경우, 외부 에서 그 배포처로 접근 가능하지 않을 경우 업데이트는 안되겠지만, 배포한 파일을 통채로 전달해, 프로그램 설치 자체는 가능하다.

암튼 이렇게 배포르 하면.


이렇게 웹으로 접근 가능한 배포페이지가 생성된다.
여기서 "설치"버튼을 클릭하면 설치가 된다.

물론 인증키같은게 없기 때문에...


이런 보안 경고가 뜰것이다.



내가 만든 프로그램이므로 경고를 무시하고 설치를 하자.


이렇게 설치단계를 진행하면....


프로그램이 실행되고...


메뉴에도 등록되어 있을 것이다.

※참고로, 웹배포(ClickOnce) 방식으로 배포를 할경우 설치경로를 임의로 변경 할수 없다. (사용자폴더의 앱테이더 영역에 설치가 된다.) 

이렇게 배포를 한뒤에는 프로그램을 변경 했을 때.



게시... 메뉴를 이용해 배포 할 수 있다.
이렇게 새로 배포한 후 기존의 설치된 프로그램을 실행하면...


이렇게 새 버젼을 인식하고 업데이트 여부를 물어 보며, "확인"을 클릭시 새로운 버전을 다운 받아 실행이 된다.


이경우 변경된 사항만 다운 받으므로 재설치에 비해 상당히 시간을 절약 할 수 있다.
물론 배포처를 접근할 수 없을 경우에는 업데이트를 하지 않고 기존 버전이 바로 실행 된다.



2015년 2월 11일 수요일

포토샵 이미지 자연스럽게 따기

가끔 기존에 사용하고 있던 문구나 이미지를 다은 이미지에 적용 시켜야 할 필요가 있는데, 원본 PSD 파일이 있을 경우라면 별 문제가 없겠으나...

원본 파일이 없으면 이게 제법 귀찮다. 다른 이미지에 있던 일부를 다른 이미지에 붙여 넣게 되면 어떻게든 표가 나니까...

예를 들어....


기존 이미지에 있던 이 문구를 다른 이미지네 넣으면....


이렇게 되어 버리니... 왠만해선 이렇게는 못쓴다.
그래서, 자동 선택 툴같은걸로 지우는데, 간단한문구는 괜찮지만, 조금 복잡한 모양은 따낸 경계선 부분이 배경색과 앨리어싱 되어있어 깔끔하게 따지지가 않는다...

이럴때. 자동 선택툴로 선택해 놓고...


위에 있는 "Refine Edge..." 를 클릭하면... (원래 숨겨져 있지만, 선택영역을 지정하면 나온다.)


옵션은 알아서 지정하면되지만, 보통은 "Smart RAdius" 를 선택하고 "Output To" 를 "New Layer" 로 지정하고 쓴다. 이건 개인적인 취향이므로 (일일이 지정하기 귀찮고, 새 레이어를 만들어 놓는게 잘못되었을 경우 복구하기 쉬우니까...) 해보고 편한쪽을 쓰면 된다.

암튼 이렇게 하면 새로 레이어 하나가 생성되는데...


이렇게 새로뜬 레이어만 보이게 체크해놓으면....



요로케 깔끔하게 따진 이미지가 보인다.
이제 이걸 복사해서 다른 이미지에 붙여 넣으면...


이렇게 자연스러운 이미지로 붙일수 있다.
이것도 완벽한것은 아니므로 조금 씩 옵션을 변경하거나, 선택영역을 선택할때 Alias 를 조정하면서 최적의 상태를 만들어 보는게 좋다.