/// <summary> /// コンストラクタ1 /// </summary> /// <param name="fileMapName"> /// FileMapのオブジェクト名 /// </param> /// <param name="maxByteSize"> /// FileMapのバイト数(0を指定すると、全体を対象) /// ※ uintなので最大、4.294967295GBまで指定可能。 /// </param> /// <param name="updateLockName"> /// 更新ロックを行うMutexの名前 /// </param> public SharedMemory(string fileMapName, uint maxByteSize, string updateLockName) { // メンバに設定 // 各種設定を保持 this._fileMapName = fileMapName; this._maxFileMapByteSize = maxByteSize; this._updateLockName = updateLockName; this._mappedViewPointer = IntPtr.Zero; // 初期化 // FileMapを開く。 this._fileMapHandle = MMapFileWin32.OpenFileMapping( MMapFileWin32.FileMapAccess.FileMapAllAccess, false, this.FileMapName); // 戻り値のチェック if (this.FileMapHandle == IntPtr.Zero) { // 開けなかった場合、 // エラーコードをチェック if (CmnWin32.ErrorCodes.ERROR_FILE_NOT_FOUND == CmnWin32.GetLastError()) { // ファイルが存在しない場合、生成する。 this._fileMapHandle = MMapFileWin32.CreateFileMapping( //IntPtr.Zero, IntPtr.Zero, new IntPtr(-1), IntPtr.Zero, MMapFileWin32.FileMapProtection.PageReadWrite | MMapFileWin32.FileMapProtection.SectionCommit, 0, this.MaxFileMapByteSize, this.FileMapName); } else { // 戻り値のチェック if (this.FileMapHandle == IntPtr.Zero) { // 生成できなかった場合 this.Dispose(); // GC前にクリーンナップ throw new WindowsAPIErrorException( CmnWin32.GetLastError(), string.Format( WindowsAPIErrorException.MessageTemplate, "CreateFileMapping")); } else { // 生成できた場合 } } } else { // 開けた場合 } }
/// <summary>アンマネージ リソースをクリーンナップ</summary> /// <remarks> /// こちらは、ユーザ、デストラクタ(Finalizeメソッド) /// の双方が実行するClose、Disposeメソッドから実行される。 /// </remarks> private void DisposeUnManagedResources() { // MapViewのアンマップ this.Unmap(); // FileMapのハンドラをクローズする。 if (this._fileMapHandle != IntPtr.Zero) { CmnWin32.CloseHandle(this.FileMapHandle); this._fileMapHandle = IntPtr.Zero; } }
/// <summary> /// FileMapをメモリ空間にマップし、MapViewを取得する。 /// </summary> /// <param name="offset"> /// FileMapの下位オフセット(32bitに制限) /// ※ uintなので最大、4.294967295GBまで指定可能。 /// </param> /// <param name="mapViewByteSize"> /// FileMapのバイト数(0を指定すると、全体を対象) /// ※ uintなので最大、4.294967295GBまで指定可能。 /// </param> public void Map(uint offset, uint mapViewByteSize) { // チェック if (this.IsDisposed) { throw new ObjectDisposedException("SharedMemory");//, "Dispose済み。"); } // offsetHighは設定しない(32bitに制限するため)。 uint offsetHigh = 0; uint offsetLow = offset; // マイナス値や、FileMapのサイズを超える場合は、FileMapのサイズに合わせる if (mapViewByteSize < 0 || (this.MaxFileMapByteSize < mapViewByteSize)) { this._currentMapViewByteSize = this.MaxFileMapByteSize; } // 既にマップされている場合は、 if (this._mappedViewPointer != IntPtr.Zero) { // 一度アンマップしてから、 this.Unmap(); } // マップしなおす(↓)。 // FileMapをメモリ空間にマップし、 // MapViewを取得する(MapViewのアドレスを返す)。 this._mappedViewPointer = MMapFileWin32.MapViewOfFile(this.FileMapHandle, MMapFileWin32.FileMapAccess.FileMapAllAccess, offsetHigh, offsetLow, this.CurrentMapViewByteSize); // 0を指定した際の仕様に合わせて if (this._currentMapViewByteSize == 0) { this._currentMapViewByteSize = this.MaxFileMapByteSize; } // MapViewの取得エラー if (this.MappedViewPointer == IntPtr.Zero) { this.Dispose(); // GC前にクリーンナップ throw new WindowsAPIErrorException( CmnWin32.GetLastError(), string.Format( WindowsAPIErrorException.MessageTemplate, "MapViewOfFile")); } }
/// <summary>Informationエントリとしてメッセージを出力</summary> /// <param name="message">メッセージ</param> /// <param name="category">カテゴリ</param> /// <param name="eventID">eventID</param> public void Write(string message, ushort category, int eventID) { bool ret = false; // イベント・ソースの登録済みハンドルを開く IntPtr hEventLog = EventLogWin32.RegisterEventSource(null, APP_NAME); // ここでエラー(ERROR_ACCESS_DENIED )になる。 // Writing in Security log on WinXP - Sysinternals Forums // http://forum.sysinternals.com/writing-in-security-log-on-winxp_topic2804.html CmnWin32.ErrorCodes ec = CmnWin32.GetLastError(); // セキュリティ・ログに書き込み ret = EventLogWin32.ReportEvent( hEventLog, EVENTLOG_INFORMATION_TYPE, category, eventID, IntPtr.Zero, 1, 0, new string[] { message }, IntPtr.Zero); // イベント・ソースの登録済みハンドルを閉じる ret = EventLogWin32.DeregisterEventSource(hEventLog); }
/// <summary>測定終了メソッド</summary> /// <returns>処理が成功した場合:結果文字列、失敗した場合:エラーメッセージ</returns> /// <remarks>自由に利用できる。</remarks> public string EndsPerformanceRecord() { #if NETSTD this._stopwatch.Stop(); this._ExecTime = this._stopwatch.ElapsedMilliseconds.ToString(); return ("ExT:" + this._ExecTime + "[msec]" + ", CT: - [msec]" + ", KT: - [msec]" + ", UT: - [msec]"); #else try { #region 実行時間取得処理セクション // システム時刻(End) UInt64 u64ExTE = 0; long lngExTE = 0; if (QPCounterWin32.QueryPerformanceCounter(ref lngExTE) != 0) // 時間の計測を開始します。 { // 周波数(更新頻度)を取得 long lngFreq = 0; QPCounterWin32.QueryPerformanceFrequency(ref lngFreq); // 秒単位 double dblTemp = ((lngExTE - LngExTS) * 1.0 / lngFreq); // 1s → 100(ns)に合わせる。 dblTemp = dblTemp * 1000 * 1000 * 10; // 整数値に変更 u64ExTE = (UInt64)Math.Round(dblTemp); } else// 高分解能のカウンタはサポートされません。 { // 100ns間隔(精度は低い) u64ExTE = Convert.ToUInt64(DateTime.Now.Ticks); } #endregion #region CPU時間取得処理セクション // カレントスレッドのハンドルを返す(IDではないので注意)。 IntPtr iptHdr; iptHdr = CmnWin32.GetCurrentThread(); // スレッドの作成時刻 System.Runtime.InteropServices.ComTypes.FILETIME ftCreateTime; // スレッドの終了時刻 System.Runtime.InteropServices.ComTypes.FILETIME ftDELETETime; // カーネル時間 System.Runtime.InteropServices.ComTypes.FILETIME ftKernelTime; // ユーザ時間 System.Runtime.InteropServices.ComTypes.FILETIME ftUserTime; // 初期化が必要? ftCreateTime.dwHighDateTime = 0; ftCreateTime.dwLowDateTime = 0; ftDELETETime.dwHighDateTime = 0; ftDELETETime.dwLowDateTime = 0; ftKernelTime.dwHighDateTime = 0; ftKernelTime.dwLowDateTime = 0; ftUserTime.dwHighDateTime = 0; ftUserTime.dwLowDateTime = 0; // Win32 API関数(GetCurrentThread) QPCounterWin32.GetThreadTimes(iptHdr, ref ftCreateTime, ref ftDELETETime, ref ftKernelTime, ref ftUserTime); // 計算用の領域 UInt32 u32KTH; UInt32 u32KTL; UInt32 u32UTH; UInt32 u32UTL; // 変換(int32 ⇒ uint32) u32KTH = Convert.ToUInt32(ftKernelTime.dwHighDateTime); u32KTL = Convert.ToUInt32(ftKernelTime.dwLowDateTime); u32UTH = Convert.ToUInt32(ftUserTime.dwHighDateTime); u32UTL = Convert.ToUInt32(ftUserTime.dwLowDateTime); // CPU時間:(uint64 * uint32) + uint64 ⇒ uint64(オーバーフローはしない) // カーネル時間(End) UInt64 u64KTE; u64KTE = Convert.ToUInt64((u32KTH * U64HIBIT) + u32KTL); // ユーザ時間(End) UInt64 u64UTE; u64UTE = Convert.ToUInt64((u32UTH * U64HIBIT) + u32UTL); #endregion #region 出力文字列作成セクション // 当該処理の実行時間を算出 UInt64 u64ExT; u64ExT = u64ExTE - U64ExTS; // 当該処理のCPU(カーネル)時間を算出 UInt64 u64KT; u64KT = u64KTE - U64KTS; // 当該処理のCPU(ユーザ)時間を算出 UInt64 u64UT; u64UT = u64UTE - U64UTS; // 当該処理のCPU時間を算出 // ※ オーバーフローは無いはず... UInt64 u64CT; u64CT = u64KT + u64UT; // 初期化 U64ExTS = 0; U64KTS = 0; U64UTS = 0; // 測定結果を文字列で返す double temp; // 四捨五入(msecの整数) temp = Math.Floor((u64ExT * 0.1 * 0.001) + 0.5); this._ExecTime = temp.ToString(); temp = Math.Floor((u64CT * 0.1 * 0.001) + 0.5); this._CpuTime = temp.ToString(); temp = Math.Floor((u64KT * 0.1 * 0.001) + 0.5); this._CpuKernelTime = temp.ToString(); temp = Math.Floor((u64UT * 0.1 * 0.001) + 0.5); this._CpuUserTime = temp.ToString(); return ("ExT:" + this._ExecTime + "[msec]" + ", CT:" + this._CpuTime + "[msec]" + ", KT:" + this._CpuKernelTime + "[msec]" + ", UT:" + this._CpuUserTime + "[msec]"); #endregion } catch (Exception ex) { // ランタイムエラー。 return(ex.Message); } #endif }
/// <summary>測定開始メソッド</summary> /// <returns>処理が成功した場合:True、失敗した場合:False</returns> /// <remarks>自由に利用できる。</remarks> public bool StartsPerformanceRecord() { #if NETSTD this._stopwatch = new Stopwatch(); this._stopwatch.Start(); #else #region メンバ変数を初期化する // 実行時間 this.U64ExTS = 0; this.LngExTS = 0; // QueryPerformanceCounter用 // CPU時間 this.U64KTS = 0; this.U64UTS = 0; // 測定結果の保存用メンバ変数の初期化 this._ExecTime = ""; this._CpuTime = ""; this._CpuKernelTime = ""; this._CpuUserTime = ""; #endregion try { #region 実行時間取得処理セクション // システム時刻(Start) if (QPCounterWin32.QueryPerformanceCounter(ref LngExTS) != 0) // 時間の計測を開始します。 { } else// 高分解能のカウンタはサポートされません。 { // 100ns間隔(精度は低い) U64ExTS = Convert.ToUInt64(DateTime.Now.Ticks); } #endregion #region CPU時間取得処理セクション // カレントスレッドのハンドルを返す(IDではないので注意)。 IntPtr iptHdr; iptHdr = CmnWin32.GetCurrentThread(); // スレッドの作成時刻 System.Runtime.InteropServices.ComTypes.FILETIME ftCreateTime; // スレッドの終了時刻 System.Runtime.InteropServices.ComTypes.FILETIME ftDELETETime; // カーネル時間 System.Runtime.InteropServices.ComTypes.FILETIME ftKernelTime; // ユーザ時間 System.Runtime.InteropServices.ComTypes.FILETIME ftUserTime; // 初期化が必要? ftCreateTime.dwHighDateTime = 0; ftCreateTime.dwLowDateTime = 0; ftDELETETime.dwHighDateTime = 0; ftDELETETime.dwLowDateTime = 0; ftKernelTime.dwHighDateTime = 0; ftKernelTime.dwLowDateTime = 0; ftUserTime.dwHighDateTime = 0; ftUserTime.dwLowDateTime = 0; // Win32 API関数(GetCurrentThread) QPCounterWin32.GetThreadTimes(iptHdr, ref ftCreateTime, ref ftDELETETime, ref ftKernelTime, ref ftUserTime); // 計算用の領域 UInt32 u32KTH; UInt32 u32KTL; UInt32 u32UTH; UInt32 u32UTL; // 変換(int32 ⇒ uint32) u32KTH = Convert.ToUInt32(ftKernelTime.dwHighDateTime); u32KTL = Convert.ToUInt32(ftKernelTime.dwLowDateTime); u32UTH = Convert.ToUInt32(ftUserTime.dwHighDateTime); u32UTL = Convert.ToUInt32(ftUserTime.dwLowDateTime); // CPU時間:(uint64 * uint32) + uint64 ⇒ uint64(オーバーフローはしない) // カーネル時間(Start) U64KTS = Convert.ToUInt64((u32KTH * U64HIBIT) + u32KTL); // ユーザ時間(Start) U64UTS = Convert.ToUInt64((u32UTH * U64HIBIT) + u32UTL); #endregion } catch { // ランタイムエラー。 return(false); } finally { } #endif return(true); }
/// <summary> /// ASP.NET で偽装ユーザーのコンテキストで実行されるプロセスを生成する /// http://support.microsoft.com/kb/889251/ja /// </summary> /// <param name="commandLinePath">コマンドライン</param> /// <param name="currentDirectory">カレント・ディレクトリ</param> /// <param name="impersonationLevel">偽装レベル</param> /// <param name="errorInfo">エラー情報</param> /// <returns> /// ・true:成功 /// ・false:失敗 /// </returns> public static bool CreateProcessAsImpersonationUser( string commandLinePath, string currentDirectory, SecurityWin32.SECURITY_IMPERSONATION_LEVEL impersonationLevel, out string errorInfo) { // エラー情報の初期化 errorInfo = ""; // 失敗するので初期化 if (string.IsNullOrEmpty(currentDirectory)) { currentDirectory = Environment.GetEnvironmentVariable( "SystemRoot", EnvironmentVariableTarget.Process); } // トークン IntPtr token = IntPtr.Zero; // 継承可能にする。 IntPtr tokenDuplicate = IntPtr.Zero; // 戻り値 bool ret; // 偽装ユーザのアカウント・トークン token = WindowsIdentity.GetCurrent().Token; // SECURITY_ATTRIBUTES構造体 SecurityWin32.SECURITY_ATTRIBUTES sa = new SecurityWin32.SECURITY_ATTRIBUTES(); // Security Descriptor sa.lpSecurityDescriptor = IntPtr.Zero; // = (IntPtr)0; // Security Descriptorのハンドルは継承不可能 sa.bInheritHandle = false; // サイズ sa.Length = Marshal.SizeOf(sa); try { // 偽装アクセストークンハンドルは、 // CreateProcessAsUserに指定できないため、 // DuplicateTokenExでプライマリ・トークンに変換する ret = SecurityWin32.DuplicateTokenEx( token, (uint)SecurityWin32.ACCESS_MASK.GENERIC_ALL, ref sa, (int)impersonationLevel, (int)SecurityWin32.TOKEN_TYPE.TokenPrimary, ref tokenDuplicate); // 戻り値判定 if (ret) { // true(成功) // STARTUPINFO構造体 ProcessWin32.STARTUPINFO si = new ProcessWin32.STARTUPINFO(); // デスクトップ名 si.lpDesktop = ""; // サイズ si.cb = Marshal.SizeOf(si); // PROCESS_INFORMATION構造体 ProcessWin32.PROCESS_INFORMATION pi = new ProcessWin32.PROCESS_INFORMATION(); // 偽装可能にしたトークンを指定してプロセス起動 ret = ProcessWin32.CreateProcessAsUser( tokenDuplicate, null, commandLinePath, ref sa, ref sa, false, 0, IntPtr.Zero, currentDirectory, ref si, out pi); // 戻り値判定 if (ret) { // true(成功) CmnWin32.CloseHandle(pi.hProcess); CmnWin32.CloseHandle(pi.hThread); // 偽装可能にしたトークンのハンドラを閉じる ret = CmnWin32.CloseHandle(tokenDuplicate); } else { // asp.net - Running cscript.exe from C# .ashx does not execute code in vbscript file - Stack Overflow // http://stackoverflow.com/questions/3842020/running-cscript-exe-from-c-sharp-ashx-does-not-execute-code-in-vbscript-file // false(失敗) errorInfo = "CreateProcessAsUser failed with " + Marshal.GetLastWin32Error() + ": if 1314, make sure user is a member 'Replace a process level token' Control Panel -> Administrative Tools -> Local Security Settings."; } } else { // false(失敗) errorInfo = "DuplicateTokenEx failed with " + Marshal.GetLastWin32Error(); } } finally { // 失敗(例外発生)時など。 // トークンハンドル、 // 偽装アクセストークンハンドルをクローズ if (token != IntPtr.Zero) { CmnWin32.CloseHandle(token); } if (tokenDuplicate != IntPtr.Zero) { CmnWin32.CloseHandle(tokenDuplicate); } } // false(失敗) return(false); }
/// <summary> /// ユーザ名・ドメイン・パスワードで偽装する。 /// </summary> /// <param name="userName">ユーザ名</param> /// <param name="domain">ドメイン</param> /// <param name="password">パスワード</param> /// <param name="impersonationLevel">偽装レベル</param> /// <param name="errorInfo">エラー情報</param> /// <returns> /// ・true:成功 /// ・false:失敗 /// </returns> public bool ImpersonateValidUser( string userName, string domain, string password, SecurityWin32.SECURITY_IMPERSONATION_LEVEL impersonationLevel, out string errorInfo) { // エラー情報の初期化 errorInfo = ""; // ワーク WindowsIdentity tempWindowsIdentity; // トークンのハンドラ IntPtr token = IntPtr.Zero; IntPtr tokenDuplicate = IntPtr.Zero; try { // クライアントアプリケーションによる偽装を終了。 if (SecurityWin32.RevertToSelf()) { // RevertToSelf成功 // 偽装する。 // トークンハンドルを取得 if (SecurityWin32.LogonUserA(userName, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref token) != 0) { // LogonUserA成功 // 偽装アクセストークンハンドルを作成 if (SecurityWin32.DuplicateToken(token, impersonationLevel, ref tokenDuplicate) != 0) { // DuplicateToken成功 // 偽装アクセストークンを使用して偽装する。 tempWindowsIdentity = new WindowsIdentity(tokenDuplicate); this.impersonationContext = tempWindowsIdentity.Impersonate(); if (this.impersonationContext != null) { // Impersonate成功 // 正常終了 return(true); } else { // Impersonate失敗 errorInfo = "Impersonate failed"; } } else { // DuplicateToken失敗 errorInfo = "DuplicateToken failed with " + Marshal.GetLastWin32Error(); } } else { // LogonUserA失敗 errorInfo = "LogonUserA failed with " + Marshal.GetLastWin32Error(); } } else { // RevertToSelf失敗 errorInfo = "RevertToSelf failed with " + Marshal.GetLastWin32Error(); } } finally { // 失敗(例外発生)時など。 // トークンハンドル、 // 偽装アクセストークンハンドルをクローズ if (token != IntPtr.Zero) { CmnWin32.CloseHandle(token); } if (tokenDuplicate != IntPtr.Zero) { CmnWin32.CloseHandle(tokenDuplicate); } } // 異常終了 return(false); }
/// <summary>クライアント生成 - Writeスレッド関数</summary> private void WriteSharedMemory() { // 共有メモリ(サーバ) SharedMemory sm = null; // スレッドID int managedThreadId = Thread.CurrentThread.ManagedThreadId; try { // 共有メモリを生成(256バイト) sm = new SharedMemory("my-sm", 256, "my-mtx"); // マップ sm.Map(0, 0); // ロック sm.Lock(); // システム時間、ローカル時間の「Manage SYSTEMTIME構造体」 SYSTEMTIME[] csts = new SYSTEMTIME[2]; // システム時間 CmnWin32.GetSystemTime(out csts[0]); string systemTime = string.Format("{0:0000}/{1:00}/{2:00} {3:00}:{4:00}:{5:00}.{6:000}", csts[0].Year, csts[0].Month, csts[0].Day, csts[0].Hour, csts[0].Minute, csts[0].Second, csts[0].Milliseconds); // ローカル時間 CmnWin32.GetLocalTime(out csts[1]); string localTime = string.Format("{0:0000}/{1:00}/{2:00} {3:00}:{4:00}:{5:00}.{6:000}", csts[1].Year, csts[1].Month, csts[1].Day, csts[1].Hour, csts[1].Minute, csts[1].Second, csts[1].Milliseconds); // 共有メモリを初期化 sm.SetMemory(CmnClass.InitBuff(256), 256); // マーシャリング(「Unmanage SYSTEMTIME構造体」のバイト表現を取得) //// (1) //SYSTEMTIME cst = new SYSTEMTIME(); //int sizeCst = Marshal.SizeOf(cst); //byte[] cstBytes = new byte[sizeCst]; //byte[] cstsBytes = new byte[sizeCst * 2]; //Array.Copy(CustomMarshaler.StructureToBytes(csts[0]), 0, cstsBytes, 0, sizeCst); //Array.Copy(CustomMarshaler.StructureToBytes(csts[1]), 0, cstsBytes, sizeCst * 1, sizeCst); // (2) byte[] cstsBytes = CustomMarshaler.StructuresToBytes(new object[] { csts[0], csts[1] }, 2); // 共有メモリへ書き込む。 sm.SetMemory(cstsBytes, cstsBytes.Length); // 送信メッセージを表示 this.SetResult_Client( string.Format("({0})送信:{1}", managedThreadId, "\r\nsystemTime:" + systemTime + "\r\nlocalTime:" + localTime)); } catch (Exception ex) { // エラーを表示 this.SetResult_Client( string.Format("({0})エラー:{1}", managedThreadId, ex.ToString())); } finally { if (sm != null) { // 共有メモリをクローズ // アンロック&マネージ・アンマネージリソースの解放 sm.Close();// ←コメントアウトするとGC任せになるが、ミューテックスの解放が遅れる! } } }