|
分類:[C#]
[環境]
・Windows7 64bit
・Visual Studio Express 2013 for Windows Desktop
・Windowsフォームアプリケーション (C#)
[現象/疑問]
下に記載した条件で、一時ファイル作成後にアプリケーション設定を取得しようとすると、例外(SettingsPropertyNotFoundException)が発生します。
ただし、10回に1回くらいの確率で、例外が発生せずに動作することがあります。
色々試してみると、[条件]の下に記載した方法だと例外が発生しなくなったのですが(※1)
一時ファイルの作成と、アプリケーション設定との関連がわかりません。
(※1 5〜10回ほど実行した限りでは発生しなかった)
なぜ例外が発生したのでしょうか。
一時ファイルの作成と、アプリケーション設定とに何か関連があるのでしょうか。
[条件]
・.NET Framework 3.5
・Win32APIのGetTempFileNameで一時ファイル作成後に
アプリケーション設定を取得しようとする
・一時ファイル作成前にはアプリケーション設定の取得を1度もしていない
-> プロジェクトのプロパティから「対象のフレームワーク」を 4.0 や 4.5 にすると
例外は発生しませんでした。
-> 一時ファイル作成をWin32APIではなく System.IO.Path.GetTempFileName に置き換えた場合も
例外は発生しませんでした。
-> 一時ファイル作成より前にアプリケーション設定を取得したことがあると
一時ファイル作成後でも、アプリケーション設定を取得できました。
[例外 1]
型 'System.AccessViolationException' のハンドルされていない例外が System.dll で発生しました
追加情報:保護されているメモリに読み取りまたは書き込み操作を行おうとしました。他のメモリが壊れていることが考えられます。
[例外 2] (自動生成されたSettingsクラスの中に以下の情報が入っていました)
'this.iCountRun' は、型 'System.Configuration.SettingsPropertyNotFoundException' の例外をスローしました。
[例外発生手順]
1) プロジェクト作成 (Windowsフォームアプリケーション)
2) 対象のフレームワークを「.NET Framework 3.5」に変更
3) アプリケーション設定に int型で「iCountRun」を設定(スコープ:ユーザ、初期値:0)
4) 自動生成された Form1 に下記コードを挿入
5) 実行 -> 起動時に例外が発生する
[System.Runtime.InteropServices.DllImport("Kernel32.dll")]
private static extern uint GetTempFileName(string sPath, string sPrefix, uint uiUnique, StringBuilder bufFileName);
public Form1()
{
InitializeComponent();
// 試したこと その1
// (1)の前にアプリケーション設定を取得すると
// (2)でも問題なく取得できるようになる
// int iCountDummy = Properties.Settings.Default.iCountRun;
// (1) 一時ファイルを作成
string sFileNameLog = GetTempFileName();
System.Console.WriteLine(sFileNameLog);
// 試したこと その2
// もしかするとアプリケーション設定も一時ファイルを使用していて
// タイミングが影響しているのかと思い Sleep を入れてみたが
// 例外発生は解消されなかった
// System.Threading.Thread.Sleep(3000);
// (2) アプリケーション設定を取得(ここで例外発生)
int iCount = Properties.Settings.Default.iCountRun;
iCount++;
Properties.Settings.Default.iCountRun = iCount;
Properties.Settings.Default.Save();
}
private static string GetTempFileName()
{
// 一時ファイルを作成する
// 接頭辞を指定するためにWin32APIを使用
string sPrefix = System.Windows.Forms.Application.ProductName;
string sPathTemp = System.IO.Path.GetTempPath();
StringBuilder bufFileName = new StringBuilder();
uint uiRet = 0;
// 試したこと その3
// ↓この1文をコメントアウトすると例外が発生しなくなる
uiRet = GetTempFileName(sPathTemp, sPrefix, 0, bufFileName);
string sFileName = null;
if (uiRet != 0)
{
sFileName = bufFileName.ToString();
}
// 試したこと その4
// 上記の代わりに下記の方法で一時ファイルを作成した場合も
// 例外は発生しなかった
// string sFileName = System.IO.Path.GetTempFileName();
return sFileName;
}
|