C#で現在、メールソフトを作成しています。メールの送信に関しては、namespaceのSystem.Net.MailにMailMessageとSmtpClientを利用すれば簡単にメールを送信することができます。
今度は、受信を行うように考えましたが、TCPClientやStreamreaderなど色々とコーディングをしなくてはなりません。送信の時と比較すると、コード量が約10倍になります。
なぜ、送信は簡単に実現できるのに、受信ができないのかとちょっと考えると、送信に関しては様々なアプリケーションであります。ただ、受信に関しては特にメールソフトがあれば、問題ないので、簡単にする必要がないのではと思います。それ以外にも商品戦略上のこともありそうですが。
メールソフトを作成していると、メールサーバーやSMTPやPOPといったプロトコルも理解することができるので、勉強になります。
今度は、受信を行うように考えましたが、TCPClientやStreamreaderなど色々とコーディングをしなくてはなりません。送信の時と比較すると、コード量が約10倍になります。
なぜ、送信は簡単に実現できるのに、受信ができないのかとちょっと考えると、送信に関しては様々なアプリケーションであります。ただ、受信に関しては特にメールソフトがあれば、問題ないので、簡単にする必要がないのではと思います。それ以外にも商品戦略上のこともありそうですが。
メールソフトを作成していると、メールサーバーやSMTPやPOPといったプロトコルも理解することができるので、勉強になります。
Windows VistaでC#のプログラムからあるDLLをコールすると「保護されているメモリに書き込みできません。(Access Violation)」が発生しました。
色々と調べていて、WindowsXPのSP2以降についたデータ実行防止(DEP)によって、エラーが表示されることがわかりました。
それも、.NET Framework2.0のSP1以降でビルドした実行ファイルの場合にこの現象が発生します。次に選択するものを除くすべてのプログラム...で実行ファイルを追加しようと思っても「DEPを有効にして実行する必要があります。DEPを無効にすることができません」警告メッセージが表示されます。
試しに、SPなしでビルドすると、追加することができて、正常にDLLをコールすることができます。
どうもこれは、.NET Framework2.0のSP1以降からDEPの設定を有効にするようになったことが影響しています。
調べてもC++ではリンカの設定がありますが、C#の場合には、DEPを無効に設定する機能がありません。
そこで、どのようにするかというと、コマンドプロンプトで、以下のように入力すれば、DEPを無効にした実行ファイルを作成することができます。
Visual Studioのインストールフォルダ\Common\\tools\vsvars32.bat
editbin.exe /NXCOMPAT:NO "指定したい実行ファイル名"
それにしても突然発生したので、原因が2日くらい悩みました。
この変更にはかなりビックリしました。
色々と調べていて、WindowsXPのSP2以降についたデータ実行防止(DEP)によって、エラーが表示されることがわかりました。
それも、.NET Framework2.0のSP1以降でビルドした実行ファイルの場合にこの現象が発生します。次に選択するものを除くすべてのプログラム...で実行ファイルを追加しようと思っても「DEPを有効にして実行する必要があります。DEPを無効にすることができません」警告メッセージが表示されます。
試しに、SPなしでビルドすると、追加することができて、正常にDLLをコールすることができます。
どうもこれは、.NET Framework2.0のSP1以降からDEPの設定を有効にするようになったことが影響しています。
調べてもC++ではリンカの設定がありますが、C#の場合には、DEPを無効に設定する機能がありません。
そこで、どのようにするかというと、コマンドプロンプトで、以下のように入力すれば、DEPを無効にした実行ファイルを作成することができます。
Visual Studioのインストールフォルダ\Common\\tools\vsvars32.bat
editbin.exe /NXCOMPAT:NO "指定したい実行ファイル名"
それにしても突然発生したので、原因が2日くらい悩みました。
この変更にはかなりビックリしました。
あるサンプルプログラムで、GCを2回コールしないと、GetTotalMemory内のメモリが破棄されないところですが、どうもGC.Collectをコールしてもすぐに、ガベージコレクションが発生するわけではないという結論になりました。
私もこれは、非常に自信があるわけでなく、先輩に相談してもやはり同様のことが得られたので、たぶんそうではないかということになりました。
メモリ管理からは開放されて非常に楽ではありますが、ブラックボックスになっている部分が多々あるので、自分で管理してもいいのかなと少しだけ思いました。
今、メモリ管理のブログラムを作成したら、まちがいなくメモリリークはするだろうなと思います。
私もこれは、非常に自信があるわけでなく、先輩に相談してもやはり同様のことが得られたので、たぶんそうではないかということになりました。
メモリ管理からは開放されて非常に楽ではありますが、ブラックボックスになっている部分が多々あるので、自分で管理してもいいのかなと少しだけ思いました。
今、メモリ管理のブログラムを作成したら、まちがいなくメモリリークはするだろうなと思います。
今日、List<参照型>にデータを追加して、GCを強制的に発生させた時に、GCを一度コールしただけでは、ガーベジコレクション対象のオブジェクトが破棄されないという現象がありました。(GC.GetTotalMemoryの値が0でない)
以下にサンプルを示します。非常に不思議なのが、stringも参照型なのに、List<string>は正常に動作するのに、独自で作成したクラスの場合には破棄されません。GCのところはサンプルのようにするとGC.GetTotalMemoryの値が0になります。
最初に、GCが別スレッドになっていて、遅延発生かなとおもい、しばらく待っていてもだめでした。
internal class 参照
{
public 参照(int 値)
{
m_数値[0] = 値.ToString();
}
~参照()
{
}
private string[] m_数値 = new string[1000];
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private const int カウント = 100000;
private void button1_Click(object sender, EventArgs e)
{
List<string> List = new List<string>();
for (int i = 0; i < カウント; i++)
List.Add(i.ToString());
}
private void button2_Click(object sender, EventArgs e)
{
List<参照> List = new List<参照>();
for (int i = 0; i < カウント; i++)
List.Add(new 参照(i));
}
private void button3_Click(object sender, EventArgs e)
{
long メモリ = GC.GetTotalMemory(false) / 1024 / 1024;
MessageBox.Show(メモリ.ToString());
GC.Collect();
Thread.Sleep(1000);
GC.Collect();
メモリ = GC.GetTotalMemory(false) / 1024 / 1024;
MessageBox.Show(メモリ.ToString());
}
}
以下にサンプルを示します。非常に不思議なのが、stringも参照型なのに、List<string>は正常に動作するのに、独自で作成したクラスの場合には破棄されません。GCのところはサンプルのようにするとGC.GetTotalMemoryの値が0になります。
最初に、GCが別スレッドになっていて、遅延発生かなとおもい、しばらく待っていてもだめでした。
internal class 参照
{
public 参照(int 値)
{
m_数値[0] = 値.ToString();
}
~参照()
{
}
private string[] m_数値 = new string[1000];
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private const int カウント = 100000;
private void button1_Click(object sender, EventArgs e)
{
List<string> List = new List<string>();
for (int i = 0; i < カウント; i++)
List.Add(i.ToString());
}
private void button2_Click(object sender, EventArgs e)
{
List<参照> List = new List<参照>();
for (int i = 0; i < カウント; i++)
List.Add(new 参照(i));
}
private void button3_Click(object sender, EventArgs e)
{
long メモリ = GC.GetTotalMemory(false) / 1024 / 1024;
MessageBox.Show(メモリ.ToString());
GC.Collect();
Thread.Sleep(1000);
GC.Collect();
メモリ = GC.GetTotalMemory(false) / 1024 / 1024;
MessageBox.Show(メモリ.ToString());
}
}
C#のDrawStringで小さいフォントで表示すると、文字が大きくなってしまう現象の続きです。
やはりDPIの値によって、文字サイズが異なることがわかりました。
PrintPreviewControlで、PrintDocumentのPrintPage内で、描画したときには正常に表示されます。
ちなみに、私のPC上でのプリンタの設定は600DPIで、画面は96DPIなので、解像度の関係でうまく表示されないことがわかりました。
ただし、不思議なのが、CreateGraphics()で作成したGraphicsに描画した場合には正常に表示されるのに、OnPaintでのPaintEventArgsのGraphicsで描画した場合には大きくなってしまうと非常に不可思議な現象が起きています。
やはりDPIの値によって、文字サイズが異なることがわかりました。
PrintPreviewControlで、PrintDocumentのPrintPage内で、描画したときには正常に表示されます。
ちなみに、私のPC上でのプリンタの設定は600DPIで、画面は96DPIなので、解像度の関係でうまく表示されないことがわかりました。
ただし、不思議なのが、CreateGraphics()で作成したGraphicsに描画した場合には正常に表示されるのに、OnPaintでのPaintEventArgsのGraphicsで描画した場合には大きくなってしまうと非常に不可思議な現象が起きています。
C#のGraphicsのDrawStringメソッドがあり、フォントサイズを0.1Fに設定して、座標値を指定すると、画像のようになってしまいます。
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
Font fnt = new Font(this.Font.FontFamily, 0.1F, FontStyle.Regular);
PointF pt = new PointF(100, 100);
e.Graphics.DrawString("あいうえお", fnt, new SolidBrush(Color.Blue), pt);
}
これがPointFではなく、RectangleFで描画する領域を設定してあげれば、正常に表示されます。
どうも調べたら、Dpiが関係していて、Dpiが大きければ正常に描画されて、標準フォント(96DPI)の場合には画像のようになります。
ちなみにこの現象は、WindowsXPで起きます。Vistaだと問題なく正常に表示されます。
そんなに小さな値を設定しても文字が見えないので、ほとんどありえないパターンだと思いますが、こんな現象もあるのだなと思いました。
それにしてもGDI+の文字のところは色々と問題があるように思います。
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
Font fnt = new Font(this.Font.FontFamily, 0.1F, FontStyle.Regular);
PointF pt = new PointF(100, 100);
e.Graphics.DrawString("あいうえお", fnt, new SolidBrush(Color.Blue), pt);
}
これがPointFではなく、RectangleFで描画する領域を設定してあげれば、正常に表示されます。
どうも調べたら、Dpiが関係していて、Dpiが大きければ正常に描画されて、標準フォント(96DPI)の場合には画像のようになります。
ちなみにこの現象は、WindowsXPで起きます。Vistaだと問題なく正常に表示されます。
そんなに小さな値を設定しても文字が見えないので、ほとんどありえないパターンだと思いますが、こんな現象もあるのだなと思いました。
それにしてもGDI+の文字のところは色々と問題があるように思います。
C#のGraphicsにDrawStringというメソッドがあります。
文字を描画するメソッドになります。
Fontの設定で、FontStyleにStrikeoutというものがあり、取り消し線を描画することができます。それ以外にも太字やイタリックなどもできます。
通常はこれで問題ありません。ただし、前後に空白を入れた場合の動作が、半角目と全角文字で異なります。画像のようになってしまいます。
この画像の外の赤枠は、Graphics.MeasureStringを利用して取得した文字のサイズを基に描画しています。
色々と調べましたが、はっきりとした原因は、GDI+のDLLまで調べることができなかったので、わかりません。
ここからは推測になります。
StringFormatに、FormatFlagsがあり、StringFormatFlags.MeasureTrailingSpacesを加味しないで、取り消し線を描画しているのではないかと思われます。
StringFormatFlags.MeasureTrailingSpacesとは、行末の空白を含めるという設定になります。GDIでサンプルを作成したところ、特に問題なかったので、GDI+からの問題のように思います。
ちなみに、Excel2007で検証したところ、セルの文字はGDIのように描画されて、オートシェイプの文字は、GDI+のように描画されることがわかりました。
文字を描画するメソッドになります。
Fontの設定で、FontStyleにStrikeoutというものがあり、取り消し線を描画することができます。それ以外にも太字やイタリックなどもできます。
通常はこれで問題ありません。ただし、前後に空白を入れた場合の動作が、半角目と全角文字で異なります。画像のようになってしまいます。
この画像の外の赤枠は、Graphics.MeasureStringを利用して取得した文字のサイズを基に描画しています。
色々と調べましたが、はっきりとした原因は、GDI+のDLLまで調べることができなかったので、わかりません。
ここからは推測になります。
StringFormatに、FormatFlagsがあり、StringFormatFlags.MeasureTrailingSpacesを加味しないで、取り消し線を描画しているのではないかと思われます。
StringFormatFlags.MeasureTrailingSpacesとは、行末の空白を含めるという設定になります。GDIでサンプルを作成したところ、特に問題なかったので、GDI+からの問題のように思います。
ちなみに、Excel2007で検証したところ、セルの文字はGDIのように描画されて、オートシェイプの文字は、GDI+のように描画されることがわかりました。
C#にPictureBoxというコンポーネントがあります。
主な使用用途として画像や線などを描画します。
これで、どうしてもチラツキがあるなと思ったので、ダブルバッファリングを利用すれば、抑えられるなと思いました。
しかし、MSDNで調べてみると、DoubleBufferedはprotectedのプロパティなので、アクセスすることができません。
色々と調べると、PictureBoxはデフォルトでDoubleBufferedがTrueになっているので、制御する必要がないことが、Reflectorで、確認するとわかりました。
つまり、チラツキは別のところにあるなということです。
PictureBoxのことが少しだけ理解が深まりました。
主な使用用途として画像や線などを描画します。
これで、どうしてもチラツキがあるなと思ったので、ダブルバッファリングを利用すれば、抑えられるなと思いました。
しかし、MSDNで調べてみると、DoubleBufferedはprotectedのプロパティなので、アクセスすることができません。
色々と調べると、PictureBoxはデフォルトでDoubleBufferedがTrueになっているので、制御する必要がないことが、Reflectorで、確認するとわかりました。
つまり、チラツキは別のところにあるなということです。
PictureBoxのことが少しだけ理解が深まりました。
今日、初めて、PropertyGridを使用して、VisualStudioのプロパティのような画面を作成しました。
最初に、モデルを作成していて、テストコードもできて、後は組み込むだけとなったときに、PropertyGridのSelectedObjectにオブジェクトを代入しました。
クラスからクラスを参照している部分も表示されるようになってだんだんと思い通りに表示されました。
しかし、ここで、どうしてもカテゴリの下に変数名が表示されてしまい、本当はカテゴリの下に、使用している変数を表示することがしたかったのにできないことがわかりました。(例:クラスA内に、クラスBがある場合に、クラスAを表示する場合)
これは色々と調べましたが、結局、クラスA内に、クラスBの処理を委譲しました。
コンポーネントの仕様上仕方のないことかもしれませんが、PropertyGridの仕様自体がどうなんだろうと思います。非常に大きなクラスができてしまうなと思いました。
最初に、モデルを作成していて、テストコードもできて、後は組み込むだけとなったときに、PropertyGridのSelectedObjectにオブジェクトを代入しました。
クラスからクラスを参照している部分も表示されるようになってだんだんと思い通りに表示されました。
しかし、ここで、どうしてもカテゴリの下に変数名が表示されてしまい、本当はカテゴリの下に、使用している変数を表示することがしたかったのにできないことがわかりました。(例:クラスA内に、クラスBがある場合に、クラスAを表示する場合)
これは色々と調べましたが、結局、クラスA内に、クラスBの処理を委譲しました。
コンポーネントの仕様上仕方のないことかもしれませんが、PropertyGridの仕様自体がどうなんだろうと思います。非常に大きなクラスができてしまうなと思いました。