달력

01

« 2008/01 »

  •  
  •  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  •  
  •  

'2008/01/17'에 해당되는 글 3

  1. 2008/01/17 내가 너의 곁에 잠시 살았다는 걸
  2. 2008/01/17 using System.IO.Ports
  3. 2008/01/17 GDI Character Set
2008/01/17 13:51

내가 너의 곁에 잠시 살았다는 걸 Thinking2008/01/17 13:51

벌써 10년이 넘은 노래가 되었네요.
참 좋아하던 노래였지요.
자꾸자꾸 들어도 지겹지 않은 몇 안되는 노래인데 말이에요...^^

Posted by -세티-
2008/01/17 09:59

using System.IO.Ports General .NET2008/01/17 09:59

using System;

using System.IO;

using System.IO.Ports;

using System.Threading;

namespace SerialPortTest

{   

             class EntryPoint   

             {      

                           static SerialPort m_com1 = new SerialPort();      

                           static SerialPort m_com2 = new SerialPort();      

                           static string m_com1Data=string.Empty;      

                           static string m_com2Data=string.Empty;      

                           [STAThread]      

                           static void Main(string[] args)      

                           {          // Assigning values for com ports         

                                        m_com1.PortName = "COM1";         

                                        m_com2.PortName = "COM2";         

                                        m_com1.ReceivedBytesThreshold = 1;         

                                        m_com2.ReceivedBytesThreshold = 1;         

                                        m_com1.BaudRate = 115200;         

                                        m_com2.BaudRate = 115200;         

                                        m_com1.DtrEnable = true;         

                                        m_com2.DtrEnable = true;         

                                        m_com1.ReceivedEvent += new SerialEventHandler(OnCom1Receive);         

                                        m_com2.ReceivedEvent += new SerialEventHandler(OnCom2Receive);         

                                        m_com1.Open();         

                                        m_com2.Open();          // create writing threads and start them         

                                        ThreadStart ts = new ThreadStart(BeginWriteCom1);         

                                        Thread t = new Thread(ts);         

                                        t.Start();         

                                        ThreadStart ts2 = new ThreadStart(BeginWriteCom2);         

                                        Thread t2 = new Thread(ts2);         

                                        t2.Start();          // wait for a bit... and then hit enter to exit         

                                        System.Threading.Thread.Sleep(1000);         

                                        Console.Read();      

                           }      

 

                           static private void BeginWriteCom1()      

                          {         

                                        m_com1.Write("Written to Com1 1/3.\n");         

                                        m_com1.Write("Written to Com1 2/3.\n");         

                                        m_com1.Write("Written to Com1 3/3.\n");      

                           }      

 

                           static private void BeginWriteCom2()      

                           {         

                                        m_com2.Write("Written to Com2 1/3\n");         

                                        m_com2.Write("Written to Com2 2/3\n");         

                                        m_com2.Write("Written to Com2 3/3\n");      

                           }                

 

                           static private void OnCom1Receive(object sender, SerialEventArgs e)      

                           {         

                                        Console.WriteLine(m_com1.ReadAvailable());      

                           }      

 

                           static private void OnCom2Receive(object sender, SerialEventArgs e)      

                           {         

                                        Console.WriteLine(m_com2.ReadAvailable());      

                           }   

             }

}

'General .NET' 카테고리의 다른 글

스마트클라이언트 서명키 만들기  (0) 2008/02/17
닷넷으로 다국어 지원 폼 만들기  (0) 2008/02/12
using System.IO.Ports  (0) 2008/01/17
GDI Character Set  (0) 2008/01/17
WinForm Events Flow  (0) 2008/01/09
Assembly DisplayName, Loading, Configuration File, Probing  (0) 2008/01/09
Posted by -세티-
2008/01/17 09:53

GDI Character Set General .NET2008/01/17 09:53

회사에서 중국어 버전의 응용 에플리케이션을 개발 중입니다.

그런데 개발툴 윈도우즈 기본 컨트롤을 이용하여 프로그램을 작성한 후 배포하니 글자가 모두 깨지더군요.

하지만 상용컴포넌트를 이용해서 만든 컨트롤들의 글자는 모두 정상으로 나와서 이상하다 싶은 생각에

두 컨트롤의 속성을 비교해 보았습니다.

그랬더니.... GDICharSet 이라는 속성이 있었습니다.

이것이 디폴트로 129 라는 값이 있는데요. 이것을 1로 변경해 줘야 하더군요.

숫자 129는 한글 캐릭터셋을 의미한다고 하네요.

위의 문제를 해결하기 위해 자료를 검색하던 중 아래의 글을 발견해서 퍼옵니다.

Dr. GUI suggests a closer look at the System.Drawing.Font class. This class is part of the System.Drawing namespace, which provides a managed class interface that encapsulates the GDI+ APIs. You can find more details about the Font class at Font Class in the MSDN Library. Upon closer examination of this class, you'll come across a property called GdiCharSet. GdiCharSet is a byte value that specifies the character set used by a Font object, and is the answer to your question.

So, let's try out the use of GdiCharSet. For now, let's assume that you already have a reference to a Font object. In this case, all you need to do is to retrieve the value of GdiCharSet, and you're cured. Well, almost. If you look at the values for GdiCharSet for a number of fonts, all you'll get back is a number. This is because GdiCharSet is a byte value representing a particular character set. Therefore, you'll need to map this byte value to the corresponding character set, as defined in WinGDI.h. WinGDI.h is a Windows header file containing, among other things, the pre-processor directives used to define GDI constants. In order to simplify your task of mapping GdiCharSet to the corresponding character set, you can use the following table, which contains a partial list of mappings.

Value of MyFont.GdiCharSet Corresponding Character Set Defined in WinGDI.h
0 ANSI_CHARSET
1 DEFAULT_CHARSET
2 SYMBOL_CHARSET
77 MAC_CHARSET
128 SHIFTJIS_CHARSET
129 HANGUL_CHARSET
130 JOHAB_CHARSET
134 GB2312_CHARSET
136 CHINESEBIG5_CHARSET
161 GREEK_CHARSET
162 TURKISH_CHARSET
163 VIETNAMESE_CHARSET
177 HEBREW_CHARSET
178 ARABIC_CHARSET
186 BALTIC_CHARSET
204 RUSSIAN_CHARSET
222 THAI_CHARSET
238 EASTEUROPE_CHARSET
255 OEM_CHARSET


What you're looking for, vis-à-vis normal font versus symbol font, depends on whether the value of GdiCharSet is 2. As the table shows, 2 corresponds to SYMBOL_CHARSET or, in other words, the Symbol character set used by symbol fonts, like Webdings or Wingdings.

Since the table provided by Dr. GUI is not exhaustive (your WinGDI.h file might contain more pre-processor directives, depending upon the character sets that your operating system supports), you might encounter a scenario where GdiCharSet contains a value that is not listed in this table. In such a case, Dr. GUI's suggestion would be to manually look up your WinGDI.h file, which is typically located at the following path (you may need to install the Platform SDK first), for the corresponding pre-processor directive.

%Program Files%\Microsoft Visual Studio .NET 2003\Vc7\PlatformSDK\Include
All the pre-processor directives relating to character sets are written sequentially. So, you need to start off by locating the following directive.

#define ANSI_CHARSET            0
Once you locate this directive, scan through the subsequent directives till you finally strike gold and come across an appropriate identifier defined as having the value contained in GdiCharSet. This identifier will give you details regarding the character set corresponding to GdiCharSet.

Dr. GUI now guides you through a typical scenario wherein you already have a Font object, and all you need to do is to retrieve GdiCharSet to determine whether your Font object is a normal font or a symbol font. This example should clearly explain the relationship between the character set used by your Font object, and GdiCharSet. Assume that you're working on a Windows application. Remember, any control that you use in your application will have a Font property, indicating the associated Font object.

To quickly test the relationship between the character set used by your Font object and GdiCharSet, perform the following steps:

In Visual Studio .NET, create a Windows application using either Microsoft® Visual C#® .NET or Microsoft® Visual Basic® .NET. Note that Form1 is created by default.
Drag a button onto Form1.
From the Properties window for this button, change the Name property to FontCheck.
From the Properties window for this button, change the Font property to any symbol font, like Webdings or Wingdings.
Add the following code to the FontCheck_Click event-handler.
C# code:

MessageBox.Show(FontCheck.Font.GdiCharSet.ToString());

Visual Basic .NET code:

MessageBox.Show(FontCheck.Font.GdiCharSet)

Build and run your application. Form1 is displayed.
Click the FontCheck button on Form1.
You should receive a message box with 2 as the text. Try the same example with Simplified Arabic (or another font on your system) in step 4, instead of a symbol font. You should receive a message box with 178 as the text. Finally, try this example after reverting, in step 4, to any of the normal fonts that you're used to (Arial, Microsoft Sans Serif, and the like). This time, your message box should display 0.

Dr. GUI hopes this is a vivid and watertight illustration of the concepts involved. The good doctor has also provided a sample prescription in the form of the code sample download for this article that will list all of the symbol fonts available on your computer.

So far, so good, as all this sounds simple enough. In fact, what Dr. GUI has prescribed so far should hold you in pretty good stead, as long as you try to retrieve GdiCharSet for a Font object whose GdiCharSet property has been set. However, you're bound to run into time-consuming roadblocks when you try to retrieve GdiCharSet for a Font object whose GdiCharSet property has not been set. In the previous example, Visual Studio .NET takes care of setting GdiCharSet for the Font object associated with your FontCheck button. Thus, you wouldn't notice anything unexpected. However, let's see what happens when you use the following code in the FontCheck_Click event-handler.

C# code:

Font MyFont = new Font("Wingdings",10);
MessageBox.Show(MyFont.GdiCharSet.ToString());

Visual Basic .NET code:

Dim MyFont As New Font("Wingdings", 10)
MessageBox.Show(MyFont.GdiCharSet)

When you run your application and then click the FontCheck button on Form1, you'd naturally expect a message box with 2 as the text, because Wingdings is, after all, a symbol font. However, you end up with a message box that has 1 as the text. Confused? Understandable but not incurable! Let Dr. GUI provide his diagnosis of this case...

When you create a Font object, GdiCharSet is set to the value of DEFAULT_CHARSET, unless, in the overloaded constructor, you explicitly specify the character set you wish to use. Checking the table discussed previously, DEFAULT_CHARSET maps to the value 1, which is exactly what the output text in your message box indicates. If, on the other hand, in the constructor of your Font object, you explicitly pass a parameter to specify the character set you'd like your Font object to use, GdiCharSet gets set with this value that you pass. So, if you want GdiCharSet to contain a meaningful value, the onus is on you to specify the appropriate parameter in the constructor when you create your Font object. Once you've created your Font object by specifying the character set to be used, you can obtain the character set used by retrieving the value of GdiCharSet.

However, supplying the character set in the constructor defeats the very purpose of what you're trying to achieve. Dr. GUI fully appreciates the redundancy involved here. Just the same, let's assume that you have a method that receives a Font object created by some code not under your control. In such a scenario, you have no way of knowing whether or not the GdiCharSet property for the Font object that your method receives contains a meaningful value. Without a clear understanding of Dr. GUI's diagnosis, you might be confused as to why a Font object, which has Wingdings as the Name property, returns 1 for the value of GdiCharSet, when you would clearly expect to get 2. Again, this is because the GdiCharSet property was not set when the Font was created.

With this apparent inconsistency clarified, it should be clear that GdiCharSet can solve only some of your ills. However, if the Font object in question is created without passing the character set value to the constructor, there's still the possibility of your being stumped. So, in order to empower you with some co-relation between your Font object and the character set used by the Font object, the Font class has a neat little method called ToLogFont.

In fact, the code that you've supplied to Dr. GUI is already on the right track. Use ToLogFont to populate a LOGFONT instance that is filled based on only some of the properties of your Font object. To brush up on LOGFONT, check out LOGFONT in the Online MSDN Library. Significantly, the lfCharSet field of your LOGFONT instance does not get set to DEFAULT_CHARSET. Rather, lfCharSet gets set to the value corresponding to the character set used by your Font object. Thus, even if the GdiCharSet property of your Font object contains DEFAULT_CHARSET, once you call ToLogFont, the lfCharSet field of your LOGFONT instance gets sets to 2—if the Name property of your Font object is Wingdings. You can now obtain what you desire by retrieving the value of the lfCharSet field of your populated LOGFONT instance.

But, before all that, you'll need to reference the System.Runtime.InteropServices namespace so that you'll be able to appropriately declare LOGFONT. So, go ahead and add the following statement to your code:

C# code:

using System.Runtime.InteropServices;

Visual Basic .NET code:

Imports System.Runtime.InteropServices

Dr. GUI couldn't help but notice that in your quest for a solution to your malady, you've already expertly converted the unmanaged LOGFONT structure to the best possible managed equivalent. Way to go! However, as Dr. GUI will explain presently, the good doctor advocates the use of a LOGFONT class, rather than a LOGFONT structure. This is where you've stumbled in your attempt and come up against a brick wall. So, let's go ahead and use your LOGFONT declaration, using "Class" and "class", instead of "Structure" and "struct", respectively.

C# code:

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
class LOGFONT
{
  public int lfHeight;
  public int lfWidth;
  public int lfEscapement;
  public int lfOrientation;
  public int lfWeight;
  public byte lfItalic;
  public byte lfUnderline;
  public byte lfStrikeOut;
  public byte lfCharSet;
  public byte lfOutPrecision;
  public byte lfClipPrecision;
  public byte lfQuality;
  public byte lfPitchAndFamily;
  [MarshalAs(UnmanagedType.ByValTStr, SizeConst=32)]
  public string lfFaceName;
}

Of course, since you're using a class rather than a structure, you'll need to explicitly instantiate your LOGFONT instance. The rest of the code advocated by Dr. GUI is in harmony with your code. So, without much further ado, let's have a look at Dr. GUI's code:

C# code:

Font MyFont = new Font("Wingdings",10);
LOGFONT MyLOGFONT = new LOGFONT();
MyFont.ToLogFont(MyLOGFONT);
// MyLOGFONT is populated.
MessageBox.Show(MyLOGFONT.lfCharSet.ToString());


Now, all that remains is to understand why you need to use a class instead of a structure.

As you've probably already noticed, ToLogFont expects you to pass an object by value. Thus, you could pass either a structure by value or a class by value and you'd still be perfectly within your rights as far as the rules relating to passing valid types. However, what you're doing is passing a System.ValueType by value, when you should be passing an object reference. Let's look at why.

The behavior you noted in your sample above (where the LOGFONT is not being filled in) is because ToLogFont receives a copy of your LOGFONT structure, which gets populated. However, these changes are not reflected in your original LOGFONT structure, which remains unpopulated. On the other hand, if you were to pass a reference to your LOGFONT instance, you would ensure that your original reference and the copy of the reference are, in fact, referring to the same LOGFONT object instance. Thus, when you declare LOGFONT as a class, the changes made to the single LOGFONT instance by ToLogFont, using a copy of your original reference, are reflected in your code.

For more details about parameter passing, check out Passing Parameters in the MSDN Library. As this piece is geared towards C# (though the concepts hold good for Visual Basic .NET too), here's something for Visual Basic .NET folks: Argument Passing Mechanism.

When you run your application, and then click the FontCheck button that is on Form1, you are rewarded for your perseverance with the result you've been waiting for all along: a message box with 2 as the text. You can try this code out for other fonts as well, and convince yourself of the veracity of this prescription. The good doctor hopes this solves the problem for you.

Thanks!
Dr. GUI wants to thank his fabulous team of specialists, including Ajay Abraham, and his dedicated nurse Maura Baughman. If Dr. GUI did surgery without y'all, the prognosis of the patients would not be good.

'General .NET' 카테고리의 다른 글

닷넷으로 다국어 지원 폼 만들기  (0) 2008/02/12
using System.IO.Ports  (0) 2008/01/17
GDI Character Set  (0) 2008/01/17
WinForm Events Flow  (0) 2008/01/09
Assembly DisplayName, Loading, Configuration File, Probing  (0) 2008/01/09
Base 64 디코딩 스크립트  (0) 2008/01/06
Posted by -세티-