原因
使用中のSQL Serverのバージョンで使用できない構文を使用していてエラーになっていた。
具体的には+=(インクリメント演算子)はSQL Server 2008以降で使えるが、
SQL Server 2005で使おうとしていて構文エラーになっていた。
対応策
・SQL Serverのバージョンを2008以上に上げる
・「@I += 1」→「@I = @I + 1」と書きかえる
使用中のSQL Serverのバージョンで使用できない構文を使用していてエラーになっていた。
具体的には+=(インクリメント演算子)はSQL Server 2008以降で使えるが、
SQL Server 2005で使おうとしていて構文エラーになっていた。
・SQL Serverのバージョンを2008以上に上げる
・「@I += 1」→「@I = @I + 1」と書きかえる
.NET Frameworkに大抵のものはあらかた揃っていますが、それでもないものもあります。そのため、.NET以外の他所の関数を読み込んで使用する方法があります。いろいろ調べたのでメモ。
あるプログラムP1からexeキックしたプログラムP2のタイトルとプロセスIDをC#で取得したい。
経緯の履歴
同じプロセス空間にあるため(インスタンスを生成したような感じらしい)、P2はP1とプロセス名が同じになってしまい、P2のMainWindowTitleが取得できなかった。P1もP2もタスクバーに表示されているからProcess.GetProcessesメソッド(プロセス一覧取得)で取れそうなのに…
↓
「タスクバー タイトル 取得 c#」とかでぐぐったが、直接的な方法をうまく検索できず、断念…
↓
「c# 子ウィンドウ 取得」あたりで検索した。
EnumChildWindows関数というものがあった。使ってみたが、ウィンドウというのがイメージと違ってコントロールのことのようで、画面の上に乗っかっているテキストフィールドやラベルなど、細々したコントロールまで含めて列挙するようで、ちょっと違うと思い、保留。
↓
最終的に、EnumWindowsを使って全列挙中から必要なものだけ取得する方法で、なんとか目的を達成できた。
画面上のすべてのウィンドウとそのタイトルを列挙する DOBON.NET
https://dobon.net/vb/dotnet/process/enumwindows.html
を参考にした。
上記ページの説明
「プロセスのメインウィンドウしか探せませんので、同じプロセスが複数のウィンドウを表示している場合は、その内1つしか取得できません。」
の通り、Process.GetProcessesメソッドでは目的の画面のMainWindowTitleが取得できなかった。
Win32 API(WindowsシステムのAPI)のEnumWindows関数を使用します。トップレベルウィンドウを列挙する関数です。(トップレベルウィンドウとは、親を持たないウィンドウのこと)
↓EnumWindows 関数(MSDN)
https://msdn.microsoft.com/ja-jp/library/cc410851.aspx
BOOL EnumWindows( WNDENUMPROC lpEnumFunc, // コールバック関数 LPARAM lParam // アプリケーション定義の値 );
公式リファレンスの「対応情報」の「インポートライブラリ:User32.lib を使用」より、「user32.dll」を読み込めばいいことがわかります。
基本的に.lib→.dllに変換すればOKです。
コールバック関数は、falseを返すか、全てを列挙し終わるまで、何度も呼ばれ続けます。
引数のlpEnumFuncにはコールバック関数へのポインタを指定します。デリゲートを渡せばOKです。デリゲートは、タイプセーフな関数ポインタまたはコールバック関数と等価です。
コールバック メソッドとしてのデリゲートのマーシャ リング https://msdn.microsoft.com/ja-jp/library/5zwkzwf4(v=vs.110).aspx
「アプリケーション定義の値」については調べたけど結局よくわかっておらず…IntPtr.Zeroを指定するサンプルばかりだったのでそうしています(´・ω・`)
using System.Runtime.InteropServices;// DllImport属性用 (略) // トップレベルウィンドウを列挙する [DllImport("user32.dll")] private static extern bool EnumWindows(EnumWindowsDelegate lpEnumFunc, IntPtr lParam); // EnumWindowsから呼び出されるコールバック関数のデリゲート private delegate bool EnumWindowsDelegate(IntPtr hWnd, IntPtr lParam);
・using System.Runtime.InteropServices;
DllImport 属性(DllImportAttribute)の定義場所の名前空間。usingで省略すると便利。
・DllImport 属性
呼び出したい関数を含むDLLを文字列で指定する。
Win32 API以外でも同様の記述になる。
・static修飾子
必須
・extern修飾子
必須
関数がC#コードの外部で実装されていることを宣言する。
一般に、アンマネージ コードを呼び出すときにDllImport 属性と共に使用される。
・publicやprivateは自由
private static int cnt = 0; // コンストラクタ public Form1() { InitializeComponent(); // ウィンドウの列挙を開始 EnumWindows(EnumerateWindows, IntPtr.Zero); Console.WriteLine(cnt.ToString());// 2840とかすごい数だった } // ウィンドウを列挙するコールバックメソッド private static bool EnumerateWindows(IntPtr hWnd, IntPtr lParam) { cnt++; // 何か処理 // 途中で列挙をやめるときは、return false;となる // ウィンドウの列挙を継続する return true; }
Windowsフォームアプリケーションを新規に作成して試しに動かしてみました。タスクバーに表示されているプログラム一覧と非常に近い一覧が取得できました。
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.Diagnostics;// プロセス用 using System.Runtime.InteropServices;// DllImport用 namespace Sample03 { public partial class Form1 : Form { #region DllImport // トップレベルウィンドウを列挙する [DllImport("user32.dll")] private static extern bool EnumWindows(EnumWindowsDelegate lpEnumFunc, IntPtr lParam); // ウィンドウの表示状態を調べる(WS_VISIBLEスタイルを持つかを調べる) [DllImport("user32.dll")] private static extern bool IsWindowVisible(IntPtr hWnd); //ウィンドウのタイトルの長さを取得する [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern int GetWindowTextLength(IntPtr hWnd); // ウィンドウのタイトルバーのテキストを取得 [DllImport("user32.dll", CharSet = CharSet.Auto)] private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount); // ウィンドウを作成したプロセスIDを取得 //[DllImport("user32")]// 「.dll」なくても動いてた [DllImport("user32.dll")] private static extern int GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId); #endregion // EnumWindowsから呼び出されるコールバック関数のデリゲート private delegate bool EnumWindowsDelegate(IntPtr hWnd, IntPtr lParam); #region 【クラス】WindowProp:ウィンドウの情報 /// <summary> /// ウィンドウの情報 /// </summary> public class WindowProp { public int ProcessId { get; set; } public string ProcessName { get; set; } public string Title { get; set; } public WindowProp() { this.ProcessId = 0; this.ProcessName = ""; this.Title = ""; } } #endregion // staticなメソッド内で使用したいプロパティにも、staticが必要 // 「静的でないフィールド、メソッド、またはプロパティ'~(略)' で、オブジェクト参照が必要です」なエラーが出る /// <summary>ウィンドウ情報のリスト</summary> private static List<WindowProp> WindowPropList { get; set; } private static int cnt = 0;// 2840とかすごい数だった private static int cntIsWindowVisible = 0;// 23 private static int cntGetWindowTextLength = 0;// 12(IsWindowVisibleで除外しない場合、218) // コンストラクタ public Form1() { InitializeComponent(); WindowPropList = new List<WindowProp>(); // ウィンドウの列挙を開始 // ここで渡したIntPtr.Zeroは、EnumerateWindowsの引数lParamに入ってくる EnumWindows(EnumerateWindows, IntPtr.Zero); foreach (var p in WindowPropList) { Console.WriteLine(p.ProcessName + " : " + p.Title); } } // ウィンドウを列挙するコールバックメソッド private static bool EnumerateWindows(IntPtr hWnd, IntPtr lParam) { cnt++; // すごい大量に列挙するので、条件つけてたくさんはじくといいようです // ウィンドウが可視かどうか調べて、表示してないのものを除外する if (IsWindowVisible(hWnd) == false) return true; cntIsWindowVisible++; //ウィンドウのタイトルの長さを取得する int textLen = GetWindowTextLength(hWnd); if (textLen == 0) return true; cntGetWindowTextLength++; //ウィンドウのタイトルを取得する var title = new StringBuilder(textLen + 1); GetWindowText(hWnd, title, title.Capacity); // ウィンドウハンドルからプロセスIDを取得 int processId; GetWindowThreadProcessId(hWnd, out processId); // プロセスIDからProcessクラスのインスタンスを取得 Process p = Process.GetProcessById(processId); Form1.WindowPropList.Add(new WindowProp() { ProcessId = processId, ProcessName = p.ProcessName, Title = title.ToString(), }); // 途中で列挙をやめるときは、return false;にする // ウィンドウの列挙を継続する return true; } } }
Console.WriteLineメソッドでコンソールに出力した文字列は、VisualStudioの「出力」ウィンドウにも表示されます。
Microsoft公式
拡張メソッド (C# プログラミング ガイド)
拡張メソッド - C# プログラミング ガイド | Microsoft Docs
大抵のものは標準で揃っているけれども、そこにない処理を個別に追加できます。
既存の型(クラスなど)にメソッドを追加できます。その追加されたメソッドのことです。
拡張メソッドを使うと、StringクラスやDatetimeクラスなど、変更できないクラスにもメソッドを追加できます。クラス自体には変更を加えないでメソッドの追加だけをできます。
→逆に言うと、変えられないクラスにメソッドを追加できる!
拡張メソッドは、静的クラスの静的メソッドとして定義します。また、追加するメソッドの最初のパラメータには、thisキーワードで拡張するクラスを指定します。
public static 拡張メソッド名( this 拡張する型, パラメータリスト ) { // 処理 }
・入れ子になってない
・ジェネリックじゃない※ジェネリッククラスの例:List
・静的クラス(static)
クラス名(ファイル名も)はなんでもいいですが、わかりやすく「~Extend」「~Ex」「~Extensions」などを付けることが多いようです。文法としては縛りはないです。(実はなんでもいい)
・静的メソッド(static)
・public
・引数の最初に「this 拡張する型名」で拡張したい型を指定
例として、「00、01、02、03…」など、左が0埋めされている文字列を「0、1、2、3…」という形に変換するメソッドを、stringの拡張メソッドとして作るとします(標準ではなかったはず…あるっけ?)。左の0をトリムするので、メソッド名はTrimLeftZeroとしてみました。
コンソールアプリを新規作成して、Mainから呼んでみます。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Util; namespace ConsoleApplication3 { class Program { static void Main(string[] args) { var list = new List<string>() { "00",// "0"にする "01",// "1"にする "02",// "2"にする }; foreach (var s in list) { string value = s.TrimLeftZero(); Console.WriteLine(value); } var today = DateTime.Today; var lastDate = today.GetLastDateOfMonth(); Console.WriteLine(today.ToString("yyyy.MM.dd") + " の月末は " + lastDate.ToString("yyyy.MM.dd")); Console.ReadLine(); } } }
同じプロジェクト内に、拡張メソッド用の別ファイルを作った場合。別ファイル(StringExtensions.cs)>StringExtensionsクラス>TrimLeftZeroメソッド
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApplication3 { public static class StringExtensions { #region TrimLeftZero:左にある連続した0を削除する /// <summary> /// 左にある連続した0を削除する /// </summary> /// <param name="value"></param> /// <returns></returns> public static string TrimLeftZero(this string value) { if (value == null) return ""; if (value == "") return ""; int i = 0; bool res = int.TryParse(value, out i); // 数字に変換できる場合は文字列にして返す if (res) return i.ToString(); // 数字に変換できない場合はそのまま返す return value; } #endregion } }
別プロジェクトにライブラリクラスとして作成した場合。プロジェクト名Util>ExtensionMethods.cs>DateTimeExtendクラス>GetLastDateOfMonthメソッド
「last day of month」は聞くけど、「last date of month」って言うのかはわかりません(´・ω・`)ある日付の月末の日付をDateTime型で取得するメソッドです。標準でありそうだけど。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Util { /// <summary> /// DateTimeの拡張メソッド /// </summary> public static class DateTimeExtend { #region GetLastDateOfMonth:日付の最終日の日付を取得する /// <summary> /// 日付の最終日の日付を取得する /// 例)「2017/10/6」から「2017/10/31」を取得する /// </summary> /// <param name="value"></param> /// <returns></returns> public static DateTime GetLastDateOfMonth(this DateTime value) { DateTime tempDate = value.AddMonths(1); DateTime lastDate = new DateTime(tempDate.Year, tempDate.Month, 1); lastDate = lastDate.AddDays(-1); return lastDate; } #endregion } }
Amazonプライム会員ならAmazonオーディブル3ヶ月無料ということで試していました。その中で「自分を操る超集中力」という本があったので聞いてみました。自分を操りたい(´・ω・`)!
オーディオブックだとどこに書いてあったか探しにくいので、うろ覚えの記憶なんですけど、本書では集中力の源となる力のことをウィルパワーと呼んでいます。たぶんwillは意志とか決めようとするとかいう意味だと思います。魔力(MP)のようなイメージで、何かをしたり、決めたり…という行動や思考で減っていきます。寝ることで回復します。総量は個人差がありますが、訓練でじわじわと総量をアップさせることができます。
その中でアロマを活用して、集中力を回復させる3つの香りが紹介されていました。
・脳への血流を良くする
ウィルパワーが回復する。
・記憶の改善
認知症の症状改善を目的として医療でも使われている。
使い方
エッセンシャルオイル(アロマオイルじゃないほうがおすすめ)をティッシュやアロマストーンなどに数滴たらして使う。(手に付かないように注意)
・リフレッシュ効果
敏捷性、集中力アップ、覚醒効果。(様々な実験で効果が認められている)
仕事や勉強による疲労・眠気を改善する。
使い方
ローズマリーと同じく、エッセンシャルオイルを使う。
他には、温かいミントティーを入れて飲む→ウィルパワー回復、リラックス効果も得られる。
・脳の認識機能、記憶力を高める
使い方
シナモンスティック(スーパーのスパイスコーナーにある)を集中したいときに嗅ぐ。
または、食事や休憩時間に、シリアルやコーヒーなどにシナモンスパウダーを振りかけて、香りづけするのもいい。
はい、影響されやすいです。エッセンシャルオイルやアロマオイル自体は家にあったので、オイルストーンを買ってみました!
2個セットなので、家と会社で使えそうです。エッセンシャルオイルが1種類選べたので、ペパーミントを選択。
おまけでサシェ付いてた。
↓2滴落とした様子。自分の周りだけ香るので良さげです。
Amazonプライム会員は3ヶ月無料ということで、オーディブルを使ってみて2ヶ月半経ちました。
やっぱりプライム会員費と比較してしまいます。プライム会員費が年間3900円に対して、オーディブルは月額1500円。さすがに高いと感じますね…。3ヶ月無料期間があったので試しましたが、費用の問題で継続には勇気が必要です(´・ω・`)
プライム会員特典がけっこう豪華なんですよね。。
オーディブルがプライム会員特典に追加されたらいいな!(´・ω・`)
コンテンツはどんどん増えている印象です!英語、ビジネス、自己啓発、瞑想が人気みたいですね。他のオーディオブックサービスを知らないのですが、今はコンテンツ不足ではないと思いますよ。