2010년 10월 27일 수요일

[InstallShield 2008] OCX 파일 수동 등록













  확장자가 ocx 인 파일을 사용하는 어플리케이션은 해당 어플리케이션을 설치할 때 ocx 파일을 시스템에 등록해주어야 한다. 이 작업이 일반적인 작업이라 InstallShield 에서 설정값만 변경하면 알아서 시스템에 등록해준다. 하지만 여러 언어의 OS에 설치해본 결과 등록될 때도, 등록되지 않을 때도 있다. 음 어떤 설정의 문제인지는 모르겠지만..








1. InstallShield 에서 OCX 파일 등록 설정










InstallShield 에서 Installation Designer → Organization → Components 로 등록할 경우, 해당 Component 프로퍼티에서 Self-Register 값을 Yes 로 하면 된다. 그러면 InstallShield가 어플리케이션을 설치하면서 해당 모듈을 자동으로 등록해 준다. 








2. 스크립트를 이용한 OCX 파일 수동 등록



 위와 같이 자동으로 등록하게 했는데 이상하게 등록이 안되는 경우가 있었다... 모든 경우를 대비하여 수동으로 등록하는 스크립트를 추가해 줬다. 











function OnEnd()


    string szProgram, szCmdLine;


begin


    szProgram = WINSYSDIR ^ "regsvr32.exe ";


    szCmdLine = TARGETDIR ^ "파일이름";


    //LongPathToShortPath (szCmdLine);


    LongPathToQuote (szCmdLine, TRUE);


    MessageBox(szCmdLine, INFORMATION);


    LaunchAppAndWait(szProgram, szCmdLine, WAIT/*LAAW_OPTION_CHANGEDIRECTORY |  LAAW_OPTION_FIXUP_PROGRAM /*LAAW_OPTION_WAIT*/); 


end;









 Windows 에서 ocx를 등록할때 regsvr32.exe 를 이용한다. 즉 Windows 실행창에서 다음과 같이 입력하여 수동으로 등록한다.


regsvr32 MyComponent.ocx


regsvr32.exe 는 Windows system 폴더에 있으므로 다음과 같이 전체 경로를 구해준다.


WINSYSDIR ^ "regsvr32.exe"; 





해당 경로로 실행시켜 주면 된다.





TARGETDIR 이 보통 "C:\Program Files" 하위에 위치하게되는데 이 값을 그냥 전달하게 되면 "C:\Program" 과 그 나머지 부분으로 짤려서 전달하게 되므로 원하는 대로 동작하지 않는다.  위의 스크립트에서 LongPathToQuote() 메소드가 이 부분을 보완해주는 함수 같긴 한데.. 아래와 같은 방법으로도 문자열이 짤리는 것을 막을 수 있다.






szOcx = "\"" + TARGETDIR ^ "MyComponent.ocx" + "\"";





2010년 10월 26일 화요일

XML 특수 문자 및 예약어 사용



 간단한 XML 작업에 대해서 큰 불편함이 없지만 특수 문자가 들어가는 문자열을 사용할 때 걸리는게 있다. 대표적인 것 몇가지만 정리해 두자.


1. C/C++ 계열 언어에서의 개행 문자 \n

\n → 


ex). <data="오류 내용 \n 잘못된 입력" /> → <data="오류 내용 &#10; 잘못된 입력" />



※ 특수 문자를 입력하는 방법


&#ASCII;




2. 예약 문자 입력

< → &lt;

> → &gt;

& → &amp;








2010년 10월 24일 일요일

[InstallShield 2008] 다국어 OS 다이얼로그 크기





 InstallShield 2008로 다국어 설치본을 제작하고 있다. 영문 String Table 및 다이얼로그 설정까지 마친 후, 실제 영문 OS에 설치해 보니 대화상자가 이상하게 크게 나타난다. 한글 OS에서는 정상적으로 보이는데...








 우선 정확한 이유는 모르겠지만 영문 다이얼로그 디자인에서 TextStyle을 적절히(?) 설정해주지 않아서 생기는 문제 같다.















Installer Designer 에서 User Interface 트리를 보자. 하위 트리에 Dialogs를 선택한 후 우측으로 사용하는 InstallShield 다이얼로그 목록이 보인다. 사용하는 다이얼로그는 굵은 글씨로 표현된다. 해당 프로젝트가 지원하는 언어에 따라 Korean, English 등이 하위 트리로 추가 된다.













해당 다이얼로그를 선택하면 우측으로 프로퍼티 목록이 보인다. 여기서 Text Style 을 보면 기본적으로 New_TextStyle로 설정되어 있다. 물론.. 이 설정은 InstallShield의 버전 및 설치된 OS 언어에 따라 다를수도 있겠다.











New_TextStyle 일 경우 한글 OS에선 잘 보이지만 영문 OS에서는 위의 경우처럼 다이얼로그가 대빵만하게 보인다. Text Style 프로퍼티에 MSSansSerif8 로 설정해 주니 영문 OS에서도 깔끔하게 다이얼로그가 출력된다.










2010년 10월 21일 목요일

[InstallShield 2008] 설치될 OS의 언어에 맞는 언어 선택









  제품이 설치될 OS의 언어가 한가지라면 다국어 작업을 해야 한다.





언어 리소스의 추가는 General Information 의 Project Properties 에서 해주면 된다. Setup Language 프로퍼티에서 국가를 추가해 주면 된다.































 설치본(Media)의 언어 선택은 어떻게 해야 할까??


Installation Designer 의 Media - Release 에서 선택해 준다. SINGLE_EXE_IMAGE 에서 Language(s), Default Language, Languages Dialog 프로퍼티 속성을 잘 정의해 준다. 여기서 집고 넘어갈 것은 Language Dialog 프로퍼티 속성을 false 로 한다면 설치본은 해당 OS의 언어로 설정되어 설치된다. 설치본에서 지원하는 언어가 없을 경우 Default Language 의 설치본으로 설치가 된다.











































2010년 10월 8일 금요일

Exception 처리



 Effective C# 에 보면 "ITEM #44. 애플리케이션에 특화된 예외 클래스를 완벽하게 작성하라." 라는 조언?! 이 있다. 아쉽게도 일하는곳에서는 배울만한 것이 아무것도 없기에 답답해 하다가 Head First C# 을 보고 Exception 처리에 대한 기본이라 생각해 정리해 본다.








 "하나의 클래스가 예외를 발생시키면 또 다른 클래스는 예외를 잡아냅니다."





 예외를 발생시킨다는 사실 뒤에 숨어있는 핵심 요지는 무엇이 잘못될 것인가 하는 것이며, 따라서 이에 대한 비상 계획을 수립할수 있다. 일반적으로는 예외를 발생 시키고 동시에 그것을 잡아내는 메소드는 그리 흔하지 않다. 하나의 메소드에서 예외를 발생시키면 다른 객체의 또 다른 메소드에서 잡아내는 경우가 대부분이다.










즉, 위와같이 Hive 객체가 BeeProfile 객체를 생성 또는 BeeProfile의 메소드를 호출 하였을 때,  BeeProfile 에서 예외가 발생하면 BeeProfile 객체 내부에서 try-catch 로 자신의 예외를 잡아서 오로지 true, false 로 결과만 리턴해 주는게 아니다. BeeProfile 객체는 예외를 발생시켜 구체적인 예외를 던지고, 피 호출자가 해당 예외를 잡아, 각각의 예외에 맞는 처리를 해주는 것이다.











 "예외 클래스 작성"





.NET 에서 발생하는 예외 클래스들의 최상위 클래스는 Exception 클래스 이다. 따라서 사용자가 정의할 예외는 Exception 클래스를 상속 받아 자신만의 예외 클래스를 작성하면 된다.










Excpetion 클래스를 상속받아 기본 생성자만을 사용할 수 있지만, 생성자에 메시지를 인자로 갖는 생성자를 사용하여 예외가 발생한 이유를 직접적으로 알릴 수 있도록 한다.









핵심 정리!!
1. 런타임 시, 실패하는 뭔가가 발생하면 어떤 문장이라도 예외를 발생 시킬 수 있다.

2. 다양한 종류의 예외가 있는데, 각각은 Exception에서 상속받은 객체를 갖고 있다. Exception이 아닌 특정한 예외를 잡아낸다.
:  다형성에 의해 Exception 으로 모든 예외를 다 받을 수 는 있지만 발생한 각각의 예외에 따른 정확한 처리를 위해 Exception 이 아닌 해당 예외 객체로 예외를 잡고 처리해야 한다.

3. 대부분은 ArgumentException 같은 .NET 이 제공하는 예외만 발생시켜도 된다. 다른 여러 종류의 예외를 사용하는 이유는 사용자에게 각각에 대한 정보를 제공해 주기 위해서 이다. "알려지지 않은 에러가 발생했습니다." 와 같은 텍스트를 보여주는 창을 띄우는 것 보다는 "선택한 폴더가 비어있습니다. 파일이 있는 다른 폴더를 선택하세요" 를 보여주는 것이 훨씬 도움이 될 것이다.










"역사상 최악의 catch 블록 : 주석"








위 예제에서 인자로 전달받은 divisor 가 0 이면 0 으로 나누는 식이 되기 때문에 DivideByZeroException 이 발생한다. 그렇다면 이 코드가 왜 최악의 catch 블록인걸까??



묻어두는 예외




위 코드에서 0 으로 나누는 경우가 발생할 경우 try-catch로 일단 예외를 잡았기 때문에 프로그램이 비정상 종료 되지는 않는다. 하지만 0으로 나누는 경우 발생하는 예외로 인한 적극적인 처리, 알림이 없기 때문에 런타임에는 도대체 quotient가 비정상적인 값이 나오는지 알 수가 없다. 비정상 적인 값이 나온다고 일일이 디버깅 할 수도 없는 노릇이고. 더 복잡한 코드에서 이런 경우가 발생하면 한참을 디버깅 할 것이다. 퇴근은 못하겠지.. 하지만 상사는 퇴근하겠지... 

협업으로 개발하는 코드를 보면 저런 코드가 상당히 많다. 내가 뭐라할 위치가 되지 않아 가만히 두고 있는데... 상당히 안타깝다...







"일시적인 해결책도 당분간은 쓸모가 있습니다."



 예외가 발생하였을 경우, 상황에 따라 개발자가 해결책을 유도하기 보다 사용자에게 오류의 원인을 알리고, 올바른 해결책의 정보를 제공해줘야 할 때가 있다. 또한 개발자도 예외 발생 시 메시지를 발생하게 하여 해당 메시지로 예외의 원인을 파악하게 할 수 있다. 예외를 처리하는 것만큼 좋은 것은 아니지만 아무것도 하지 않는 것보다는 낫다.






"프로그램이 산산히 부서지는 것은 절대 좋지 않지만, 프로그램이 왜 충돌하고 사용자의 데이터를 가지고 무슨 일을 하는지 알지 못하는 것이 더 나쁩니다. 언제나 예상할 수 있는 에러를 처리했는지 확인하고, 처리하지 못하는 것을 기록해야 하는 이유가 바로 여기 있습니다."









예외 처리를 위한 몇 가지 간단한 팁!!

1. 에러를 우아한 방식으로 처리하는 코드를 작성하세요.

2. 사용자에게 도움이 되는 에러 메시지를 보여주세요.

3. 가급적이면 내장 .NET 예외를 던지세요. 자신만의 정보를 제공해야 할 때문 사용자 정의 예외를 발생시키세요.

4.  try블록에서는 프로그램을 중단할 것 같은 코드를 작성하세요.

5. 불필요한 파일 시스템 에러는 피하세요. 스트림을 사용할 때는 항상 using 블록을 사용하세요.









cf) Head First C#

2010년 10월 5일 화요일

[InstallShield 2008] Uninstall 시 파일 삭제 결정









 기본적으로 InstallShield로 설치된 파일들은 Uninstall 시 같이 삭제 된다. 처음엔 별다른 설정 없이 이 기능이 참 맘에 들었다. 하지만 설치본도 복잡해 지면서 다른 모듈과의 연관성에 의해 삭제하면 안되는 파일이 있었다. 





 InstallShield2008에서는 Installation Designer 에서 프로퍼티를 설정하는 방법으로 쉽게 설정할 수 있다.










Installation Designer 에서 왼쪽에 보이는 Organization 트리를 펼쳐준다. Setup Design 또는 Components를 선택하면 우측으로 설치하려는 Component들의 트리 구조를 볼 수 있다. 여기서 해당 Component를 마우스로 선택하면 아래와 같이 Property를 설정할 수 있는 화면이 보여진다.













Uninstall 프로퍼티는 Uninstall 시, 해당 Component를 삭제할 것인지를 나타내는데, 기본이 Yes로 되어 있어서 Uninstall 시 파일들이 삭제되었던 것이다. 이 값을 No로 설정하면 Uninstall 시 자동으로 삭제되지 않는다.











2010년 10월 4일 월요일

Howto : Detect OS Architecture with C#

출처 : Howto : Detect OS Architecture with C#







I’ve had a problem in one of the utility applications/scripts I’ve been developing, I had to find out the Operating System Architecture, where application was running, here is the process I’ve used to do so:



   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Text;
   4:   
   5:  namespace SystemUtilities
   6:  {
   7:   // Enum to describe OS Architecture.
   8:   public enum OSArchitecture
   9:   {
  10:     X84,
  11:     X64
  12:   }
  13:   // Class to retrieve specific OS Variables. 
  14:   // And detect specific enviroiment conditions.
  15:   public class OSUtilities
  16:   {
  17:     // Function returns type of OS Architecture.
  18:     public OSArchitecture GetOSArchitecture()
  19:     {
  20:      if ( Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE") == "AMD64" 
  21:        || Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE") == "IA64"
  22:        || Environment.GetEnvironmentVariable("PROCESSOR_ARCHITEW6432") == "AMD64"
  23:        || Environment.GetEnvironmentVariable("PROCESSOR_ARCHITEW6432") == "IA64" )
  24:      { return OSArchitecture.X64; }
  25:   
  26:      return OSArchitecture.X84;
  27:     }
  28:   }
  29:  }


















cf) 참고





 OS Architecture 정보 즉 x86, x64 인지에 대한 정보는 레지스트리 HKLM\System\CurrentControlSet\Control\Session Manager\Environment 키의 PROCESSOR_ARCHITECTURE 값을 조사해도 알 수 있다. 또한 BCL System.Environment 정적 클래스를 이용하여 구할 수 도 있다. Environment.GetEnvironmentVariable 메소드를 이용하여 구할 수 있는데 약간 주의를 해주어야 한다. PROCESSOR_ARCHITECTURE 환경 변수값을 조사하면 OS Architecture 가 x86인 경우 "x86" 문자열 값을 구할 수 있지만 OS Architecture 가 x64 인 경우 구해지는 값은 "AMD64" 또는 "IA64" 값을 얻는다. 따라서 PROCESS_ARCHITECTURE 값이 "AMD64", "IA64" 인 경우 OS ARCHITECTURE가 x64이다. 


 Environment.GetEnvironmentVariable 의 두번째 매개변수로 타겟을 지정해 줄 수 있는데, 이 매개변수를 지정해 주지 않으면 실행시킨 프로세서를 기준으로 값이 얻어지므로 EnvironmentVariableTarget.Machine 을 이용해 주자.











C# region 에 대하여.

 조금 여락한 환경에서 .NET 개발을 하고 있다. 조금은 더 효과적, 체계적으로 배우고 싶은데..




C# 코드 파일은 C 계열 언어와 달리 .cs 파일 하나에 코드를 구현한다. 구현에 있어 클래스가 길어 질 수 있는데(클래스가 장대하게 길어지면 그것도 디자인을 잘못한듯) #region-#endregion을 이용하여 코드를 문서화 할 수 있다. 딱 여기까지는 익히 아는건데 도데체 어떻게 써야 잘 썼다고 말할까?! 고민하다 Open Source 인 log4net 은 어떻게 사용하나 살펴보았다. 


정답은 없지만 그래도 Open Source 의 코드는 경험 많은 개발자들의 코드이므로 도움이 될 것 같다.





 보통 클래스 내 멤버의 접근 지정자에 따라 분류한다. 










1. public, protected, private 등 접근 지정자 별로 분류


2. 같은 접근 지정자일 경우, 생성자, 프로퍼티, 필드 등 으로 분류


3. 가시성은 public 멤버를 제일 상단에 배치













또는 인터페이스의 구현, helper, static wrapper 와 같이 성격이 비슷한 것 끼리 묶을 수 도 있다.













#endregion 라인에 아무것도 써주지 않아도 되는데, #region-#endregion 부분이 길어질 경우 #endregion 만 써 놓으면 어떤 부분인지 찾아야 되는 번거러움이 있으므로 #endregion 옆에도 참고가 될 설명을 붙여준다.













인터페이스 구현 시 IDE가 #region 을 자동으로 추가해 준다. 구현하는 인터페이스 별로 분류하니 보기도 좋다.








 첨엔 #region-#endregion 으로 분류 해 놓으니 개발하는 중간에는 파일을 열 때 마다 #region 을 풀어주는게 귀찮았던 적이 있다. 귀찮아서 하지 않은 코드가 있었는데 나중에 열어보니... 어후...  나중을 위해 서라도 #region-#endregion 잘 활용해 보자

모를땐, 익숙하지 않을땐 따라하면서 배워야지!!