'개발'에 해당되는 글 25건
- 2010.09.18 ShouldSerialize 및 Reset 메서드를 사용하여 기본값 정의
- 2010.04.28 AppStylist Editors 탭 선택 에러 (혹은 UltraTimeZoneEditor 생성자 에러)
- 2009.09.10 String to Byte[]
- 2009.08.04 Form과 UserControl의 AutoScaleMode 속성
- 2009.06.12 디자인 타임에서 자식 추가 가능하게 만들기
- 2009.06.10 웹 서비스 Exception 공통 처리
- 2009.05.21 예외 계층
- 2009.05.13 이벤트 만들 시 주의사항 ( 제너릭 EventArgs에 대하여 )
- 2009.04.07 prepareStatement를 이용하여 정규식에서 이용하는 ?(물음표) 보내기
- 2009.03.31 파일 공간 미리 확보하기
- 2009.03.26 Windows Live ID SDK MSDN
- 2009.03.26 Microsoft Sync Framework MSDN
- 2009.03.23 Microsoft Sync Framework v1.0
- 2009.03.05 1초 값
- 2009.02.14 Sql2008 DB
AppStylist 프로그램을 이용하여 스킨을 설정하려고 할 때 Editors 탭을 선택하면
"동일한 키를 사용하는 항목이 이미 추가되었습니다."
라는 메시지로 에러 화면이 발생합니다.
이것이 UltraTimeZoneEditor에서 TimeZone 리스트를 가져오기 위한 작업을 할 때
다음 두 곳중 레지스트리가 존재하는 한곳의
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Time Zones
STD의 값을 키값으로 이용하고 있습니다.
이 때 이용하는 키 값이 중복이 되어서 그렇습니다.
Windows Server 2003 R2 한글 PC의 경우엔 다음 두 곳에서 중복 키가 존재했습니다.(PC마다 다를 수 있습니다.)
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\Central Europe Standard Time
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\Central European Standard Time
동일 키가 존재하면 STD값을 다르게 처리하면 됩니다.
(Windows 7의 경우에는 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\Central Europe Standard Time의 STD값 뒤에 스페이스 하나가 더 들어가 있습니다.)
다음 소스는 제가 검사할 때 이용한 소스입니다.
private static void CheckTimeZones() { string name = @"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones"; string name2 = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Time Zones"; RegistryKey key = null; key = Registry.LocalMachine.OpenSubKey(name, false); if (key == null) { key = Registry.LocalMachine.OpenSubKey(name2, false); } if (key == null) { return; } string[] subKeyNames = key.GetSubKeyNames(); if (subKeyNames == null) { return; } Dictionarydic = new Dictionary (subKeyNames.Length); RegistryKey key2 = null; for (int i = 0; i < subKeyNames.Length; i++) { name = subKeyNames[i]; if (name != null) { key2 = key.OpenSubKey(name, false); if (key2 != null) { string displayName = key2.GetValue("Display") as string; string standardName = key2.GetValue("Std") as string; try { dic.Add(standardName, displayName); } catch { throw new Exception(key2.Name + "의 Std값이 중복되었습니다."); } } } } }
보통 Byte 배열과 String 간의 변환을 할 경우 다음과 같이 이용할 것입니다.
public static String ToString(Byte[] bytes) { return Encoding.UTF8.GetString(bytes); } public static Byte[] ToBytes(String s) { return Encoding.UTF8.GetBytes(s); }
하지만 암호화한 Byte배열을 그대로 이용한다면 에러를 내뱉습니다.
그래서 다음과 같이 변환을 해야 합니다.
public static String ToString(Byte[] bytes) { return Encoding.UTF8.GetString(Encoding.Convert(Encoding.GetEncoding("iso-8859-1"), Encoding.UTF8, bytes)); } public static Byte[] ToBytes(String s) { return Encoding.Convert(Encoding.UTF8, Encoding.GetEncoding("iso-8859-1"), Encoding.UTF8.GetBytes(s)); }
우선 AutoScaleMode 속성에 대한 MSDN입니다.
http://msdn.microsoft.com/ko-kr/library/system.windows.forms.containercontrol.autoscalemode.aspx
다음은 AutoScaleMode 열거 형에 대한 MSDN입니다.
http://msdn.microsoft.com/ko-kr/library/system.windows.forms.autoscalemode.aspx
AutoSacleMode 열거 형은 None, Font, Dpi, Inherit 이렇게 4가지가 존재합니다.
None : 자동 스케일 변경 없음
Font : 폰트 사이즈에 따른 스케일 변경
Dpi : 화면 해상도 Dpi 변경에 따른 스케일 변경
Inherit : 부모의 상태를 따름
기본적으로 Form과 UserControl은 Font로 설정되어져 있습니다.
이 설정은 Font가 변경이 되면 Form과 UserControl의 크기가 재조정되고 내부의 컨트롤들의 위치도 재배치됩니다.
이렇게 되면 원하지 않는 UI가 나오게 되기 때문에 이 설정은 이용하지 않는 것이 좋겠습니다.
그냥 무조건 개발 당시의 화면으로 나오게 하고 싶으면 None을 이용하면 됩니다.
None은 윈도우의 Dpi 변경해도 동일한 화면크기로 프로그램이 실행됩니다.
현재 대부분의 모니터가 96dpi로 맞추어져서 나오기 때문에 None을 이용하여 고정하여도 되지만
나중에 나오는 모니터의 dpi가 96dpi로 나온다는 보장이 없기 때문에 Dpi를 이용하여 윈도우의 Dpi변경에 의한
자동 사이즈 변경이 가능하도록 개발하는 것이 좋겠습니다.
Dpi로 설정할 시에 주의할 점이 있습니다.
각 컨트롤의 사이즈가 자동으로 조정하지만 이미지의 사이즈는 설정한 대로 나온다는 것입니다.
이미지를 Tile옵션으로 하면 이미지컨트롤의 사이즈가 변경이 되어도 이미지 자체의 사이즈는 변경되지 않기 때문에
Stretch옵션을 이용하여 컨트롤 사이즈가 변하면 이미지도 따라 변하게 만들어 주어야 합니다.
또 한가지는 UserControl의 AutoScaleMode 속성은 Inherit으로 설정하여야 한다는 것입니다.
UserControl의 AutoScaleMode 속성도 Dpi로 할 경우에 UserControl내의 컨트롤의 사이트와 위치가
원하지 않게 나타납니다. ( 원인은 저도 모릅니다만 아마 UserControl의 AutoScaleMode가 먼저 적용된 뒤에 Form이 적용되면서 이상해 지지 않나 싶습니다. )
( 주의할점 추가 - SplitContainer를 이용할 경우에도 이상한 UI로 변경됩니다. )
앞으로 AutoScaleMode속성은 Form의 경우에는 Dpi로 UserControl의 경우에는 Inherit으로 설정하도록 합시다.
using System.Windows.Forms; using System.ComponentModel; using System.ComponentModel.Design; [Designer("System.Windows.Forms.Design.ParentControlDesigner,System.Design", typeof(IDesigner))] public partial class UserControl1 : UserControl { public UserControl1() { InitializeComponent(); } }
[Designer("System.Windows.Forms.Design.ParentControlDesigner,System.Design", typeof(IDesigner))]
이 Attribute를 이용하면 끝.
IHttpModule을 이용하여 공통 처리하는 것이 좋겠지만
웹 서비스의 경우에는 Exception을 "html/xml"으로 변경 처리하기 때문에
여기의 Error에서 Exception을 확인할 수 없습니다.
public class ExceptionManager : IHttpModule { public void Init(HttpApplication webApp) { webApp.Error += new EventHandler(webApp_Error); } protected void webApp_Error(object sender, EventArgs eventArgs) { HttpApplication webApp = (HttpApplication)sender; Exception e = webApp.Server.GetLastError().GetBaseException(); // 예외 처리 } public void Dispose() { } }
그래서 SoapExtension을 확장하여 Exception 공통 처리를 하도록 변경하여야 합니다.
public class ExceptionExtension : SoapExtension { public override object GetInitializer(Type serviceType) { return null; } public override object GetInitializer(LogicalMethodInfo methodInfo, SoapExtensionAttribute attribute) { return null; } public override void Initialize(object initializer) { } public override void ProcessMessage(SoapMessage message) { switch (message.Stage) { case SoapMessageStage.BeforeSerialize: SoapException ex = message.Exception as SoapException; if (ex != null) { // 예외 처리 } break; } } }
SoapExtension을 상속받아 추상화 부분을 작성하면 됩니다.
그 중 ProcessMessage의 message.Stage가 SoapMessageStage.BeforeSerialize이거나
SoapMessageStage.AfterSerialize이면 웹 서비스에서 발생한 Exception을 확인할 수 있습니다.
두 가지 중 BeforeSerialize을 이용한 것은 이곳에서는 Exception을 변경하여도 되지만
AfterSerialize에서는 Exception을 변경하면 안되기 때문입니다.
HttpModule의 등록장소는 Web.Config 파일의 다음과 같지만
<configuration> <system.web> <httpModules> <add name="ExceptionManager" type="Darkin.ExceptionManager, Darkin" /> </<httpModules> </system.web> <!-- IIS 7.0 <system.webServer> <modules> <add name="ExceptionManager" type="Darkin.ExceptionManager, Darkin" /> </modules> </system.webServer> --> </configuration>
SoapExtension의 경우에는 다음과 같습니다.
<configuration> <system.web> <webServices> <soapExtensionTypes> <add type="Darkin.ExceptionExtension, Darkin" priority="1" group="High" /> </soapExtensionTypes> </webServices> </system.web> </configuration>
이 이벤트 발생시 전달하는 클래스를 제너릭으로 만들면 동작은 잘 되지만
이벤트 생성 처리시에 문제가 있다.
여기서의 생성 처리시 문제란 VS가 자동으로 생성해 주는 경우이다.
void textBox1_TextChanged(object sender) { }
원래는 이렇게 생성 되어야 한다.
물론 위의 것을 아래로 수정해도 된다.
void textBox1_TextChanged(object sender, DChangeEventArgs<String> e) { }
이 문제의 해결은 제너릭으로 만들어 진 것을 다시 상속받아 제너릭이 아니게 만들면 된다.
class DTextChangeEventArgs : DChangeEventArgs<String> { public DTextChangeEventArgs(String oldValue, String newValue) : base(oldValue, newValue) { } }
물론 EventHandler<T> 도 문제가 있으므로
이것은 직접 delegate를 이용한 EventHandler를 만들어 이용하도록 하자.
//public event EventHandler<DTextChangeEventArgs> TextChanged; public delegate void DTextChangeEventHandler(object sender, DTextChangeEventArgs e); public event DTextChangeEventHandler TextChanged;
TEST 1A 란 문자열의 뒤 1A를 추출하고 싶을 때에 단 숫자가 두 자리 까지라고 한다면
"[0-9]?[0-9A-Ca-c]"정규식을 이용하여 추출하여야 합니다.
InitialContext ctx = new InitialContext(); DataSource ds = (javax.sql.DataSource)ctx.lookup("testDB"); Connection con = ds.getConnection(); PreparedStatement ps = con.prepareStatement( "Select REGEXP_SUBSTR('TEST 1A', '[0-9]?[0-9A-Ca-c]') FROM DUAL"); ps.executeQuery();
하지만 이렇게 한다면 ?에 들어갈 Parameter가 없다는 에러가 나게 됩니다.
prepareStatement의 경우 ?를 Parameter를 받도록 이용하기 때문에 ?를 그냥 보낼 수 없습니다.
이런 경우엔 Parameter로 다시 "?"를 보내면 해결할 수 있습니다.
InitialContext ctx = new InitialContext(); DataSource ds = (javax.sql.DataSource)ctx.lookup("testDB"); Connection con = ds.getConnection(); PreparedStatement ps = con.prepareStatement( "Select REGEXP_SUBSTR('TEST 1A', '[0-9]?[0-9A-Ca-c]') FROM DUAL"); ps.setString(1, "?"); ps.executeQuery();
단 유의할 사항 하나가 있다면 "?"를 Parameter넘기게 되면 ?를 대체하여 '?'가 들어가게 됩니다.
그렇게 되면 다음과 같이 이상한 쿼리가 만들어 지게 됩니다.
Select REGEXP_SUBSTR('TEST 1A', '[0-9]'?'[0-9A-Ca-c]') FROM DUAL
그렇게 때문에 다음과 같이 쿼리상에서 ? 를 그냥 넣지 않고
'||?||'로 넣어서 ?가 '?'로 변했을 때를 대비하여 넣어야 합니다.
InitialContext ctx = new InitialContext(); DataSource ds = (javax.sql.DataSource)ctx.lookup("testDB"); Connection con = ds.getConnection(); PreparedStatement ps = con.prepareStatement( "Select REGEXP_SUBSTR('TEST 1A', '[0-9]'||?||'[0-9A-Ca-c]') FROM DUAL"); ps.setString(1, "?"); ps.executeQuery();
이렇게 하면 이런 쿼리를 보내게 됩니다.
Select REGEXP_SUBSTR('TEST 1A', '[0-9]'||'?'||'[0-9A-Ca-c]') FROM DUAL
using (FileStream file = new FileStream("Text.txt", FileMode.Create, FileAccess.Write, FileShare.None)) { Console.WriteLine(file.Length); file.SetLength(1*1024*1024*1024); Console.WriteLine(file.Length); }
void FileStream.SetLength(long value) 함수를 이용하여 미리 공간 확보할 수 있습니다.
Date 타입에서 정수는 날짜 의미
소수점은 시간 의미
정수 1 차이가 날짜 하루 차이
1일 = 24시간
1시간 = 60분
1분 = 60초
1초 = 1 / 60 / 60 / 24
= 1.1574074074074074074074074074074e-5
= 0.000011574074074074074074074074074074
Sql2008 All Product Samples Without DBs
http://www.codeplex.com/SqlServerSamples/Release/ProjectReleases.aspx?ReleaseId=18648
Sql2008 AdventureWorks All Databases
http://www.codeplex.com/MSFTDBProdSamples/Release/ProjectReleases.aspx?ReleaseId=18407