- 投稿日:2020-08-17T23:48:27+09:00
【.NET】VB.NETは型推論すべきなのか
型推論とは
いまさらわざわざ書くことではないですが、一応書いておくと「代入式の右辺からコンパイラに型を推論させる(暗黙の型指定)」ってやつですね。
わざわざString(string)とかInteger(int)とかって書かずに良くなります。
まあ処理によってはコンパイラさんがうまく判断できずにObjectってされちゃったりもするので状況によっては使えませんが、使えるところでは使っていくべきものですね。
もちろん、可読性に影響が出るのであれば避けるべきですが、ここでは可読性については考慮しないものとして書きます。variable.csstring value1= "型指定"; var value2 = "型推論";variable.vbDim value1 As String = "型指定" Dim value2 = "型推論"「VB.NETは型推論すべきなのか」とは
VB.NETでも上記のコードのように型推論させることができます。
なのになぜこんなことを書いているかというとMicrosoftのコーディング規約にVB.NETでは型推論について言及がされていないからです。C#.NET: C# のコーディング規則 (C# プログラミング ガイド)
VB.NET: Visual Basic のコーディング規則うーん、Microsoftとしてはなにか思惑があるのでしょうか。
これを見て以前はVB.NETを書く時は意図的に型指定をきっちり書いていましたが、めんどくさい、めんどくさい…
型によっては横にも長くなってださいし…私は最近、VB.NETを書く機会があった時はむしろ積極的に型推論を書くようにして、なにか不都合がでるか気にしてみてますが、今のところは特にありません。
C#.NETと中間コードでも比較してみれば差(もしくは差がないこと)が分かるのかな?
「VB.NETは型推論すべきなのか」
私の意見としてはやはり型推論すべきだと思います。
型指定した場合はVB.NETの方が「Dim」、「As」といったワードを余計に多く書くことになります。
しかしながら型推論をした場合は「var」と「Dim」という差はあれど打つ文字数は同じになるのでスッキリして見えるように感じます。
打つ文字数が少なく済むならそれに越したことはありません。気になる点
Golang等の他の言語も「var」であることを考えると「Dim」であることはうーん…って感じです。
まあVB.NETは他と比べると独自路線なのでこれに限った話ではないので今更ですが。他の技術者が型推論を知らない、VB.NETで型推論できることを知らない可能性がある、という点もあります。
皆が皆、最初に学んでからさらに学ぼうという人ばかりではありません。
特にVB.NETはVB6やもっと前からやってきている人も中にはおり、そういった人にとっては混乱の種になるかもしれません(年代的に管理職になってそうですが)。あとがき
いろんな人の意見を聞いてみたいところです。
- 投稿日:2020-08-17T22:58:34+09:00
【VB.NET】Nullable型をワンライナーのIfで書いた時の挙動
左辺にNullable型、右辺にワンライナーのIfでNothingを返す
こんなソース
例なのでtextはNothingのまま、Nothingじゃなかった時の戻り値は適当に100としています。NullableIfSample.vb' 分かりやすさのために明示的に初期化します。 Dim text As String = Nothing Dim value As Integer? = If(text Is Nothing, Nothing, 100)戻り値としてはNothingまたは他の値(上の例の場合は100)にしたいってことですね。
まあ滅多にありませんがたまーにこういうことがしたいケースがあります。おとなしくIf-Elseで書けばいいんですが、無駄に行数食って見栄えが良くないのでついついワンライナーで書きたくなります。
どうなるか
Nothingじゃない時はいいとして、Nothingの場合は0が返ります。
なぜなのか、C#で同じコードを書くと分かります。NullableIfSample.csstring text = null; int? value = text == null ? default(int) : 100; // こうは書けません。 // int? value = text == null ? null : 100;NothingはC#でいうところのdefaultの機能を持つので、Integerの初期値である0になっちゃうということです。
C#の場合はVB.NETのようにnullの時にnullを返す、と書けないので発生しない問題ですが、覚えておくと良いかもしれません。どう書けば良いのか
ワンライナーで書くことを諦めるしかありません。
NullableIfSample.vbDim value As Integer? If text Is Nothing Then value = Nothing Else value = 100 End Ifうーん、行数増えて見栄えが良くない。。。
ちなみにワンライナーで書いているコードは型推論せず明示的に型指定をしていますが、型推論させようとすると通常のint型になるので注意が必要です。
あとがき
前々からなんか書こうと思ってたのと、別件でQiita使ってレポート提出することがあるのでちょっとした小ネタを書いて慣れていければと思います…
(そんな大仰な技術力はないので…)
- 投稿日:2020-08-17T22:41:58+09:00
C#でライブラリレスでJoyStick(GamePad)の入力イベントを受け取る (Windows API)
経緯
部屋を片付けていたら、いい感じのコントローラ(USB)が出てきた1。(/・ω・)/
入力デバイスとしての可能性を感じた2ので(?)、入力イベントを受け取る方法が無いか調べてみたところ、
Windows API使えばライブラリ無しで入力イベントを取得できることが分かったので、やってみました。ソースコード
using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.Drawing; using System.IO; using System.Reflection; using System.Runtime.InteropServices; using System.Windows.Forms; class GamePadTest : Form { class MyMessageFilter : IMessageFilter { const int MM_JOY1MOVE = 0x3A0;// Joystick JOYSTICKID1 changed position in the x- or y-direction. const int MM_JOY2MOVE = 0x3A1;// Joystick JOYSTICKID2 changed position in the x- or y-direction const int MM_JOY1ZMOVE = 0x3A2;// Joystick JOYSTICKID1 changed position in the z-direction. const int MM_JOY2ZMOVE = 0x3A3;// Joystick JOYSTICKID2 changed position in the z-direction. const int MM_JOY1BUTTONDOWN = 0x3B5;// A button on joystick JOYSTICKID1 has been pressed. const int MM_JOY2BUTTONDOWN = 0x3B6;// A button on joystick JOYSTICKID2 has been pressed. const int MM_JOY1BUTTONUP = 0x3B7;// A button on joystick JOYSTICKID1 has been released. const int MM_JOY2BUTTONUP = 0x3B8;// A button on joystick JOYSTICKID2 has been released. // https://docs.microsoft.com/en-us/windows/win32/multimedia/mm-joy1buttondown public bool PreFilterMessage(ref Message m) { if (m.Msg == MM_JOY1BUTTONDOWN || m.Msg == MM_JOY1BUTTONUP || m.Msg == MM_JOY1MOVE || m.Msg == MM_JOY1ZMOVE) { try{ int fwButtons = (int)m.WParam; ulong tmp = (ulong)m.LParam; // 64bit環境で31bit目が1のIntPtrをuintにキャストするとOverflowExceptionが発生するっぽい???ので対策。 int xPos = (int)( tmp &0xFFFF); int yPos = (int)((tmp>>16)&0xFFFF); Console.Write("Message:0x"); Console.WriteLine(m.Msg.ToString("X3")); Console.Write("buttons:0x"); Console.WriteLine(fwButtons.ToString("X8")); Console.Write("x:"); Console.WriteLine(xPos); Console.Write("y:"); Console.WriteLine(yPos); } catch(OverflowException e) { Console.WriteLine(e); } } return false; } } private static class NativeMethods { [DllImport("winmm.dll")] public static extern int joyGetNumDevs(); [DllImport("winmm.dll")] public static extern int joyGetPosEx(int uJoyID, ref JOYINFOEX pji); // hwnd ... Handle to the window to receive the joystick messages. // uJoyID ... Identifier of the joystick to be captured. Valid values for uJoyID range from zero (JOYSTICKID1) to 15. // uPeriod ... Polling frequency, in milliseconds. // fChanged ... Change position flag. Specify TRUE for this parameter to send messages only when the position changes by a value greater than the joystick movement threshold. Otherwise, messages are sent at the polling frequency specified in uPeriod. [DllImport("winmm.dll")] public static extern int joySetCapture(IntPtr hwnd, int uJoyID, int uPeriod, int fChanged); [DllImport("winmm.dll")] public static extern int joyReleaseCapture(int uJoyID); } const int JOYSTICKID1 = 0; const int MMSYSERR_BADDEVICEID = 2; // The specified joystick identifier is invalid. const int MMSYSERR_NODRIVER = 6; // The joystick driver is not present. const int MMSYSERR_INVALPARAM = 11; // An invalid parameter was passed. const int JOYERR_PARMS = 165; // The specified joystick identifier is invalid. const int JOYERR_NOCANDO = 166; // Cannot capture joystick input because a required service (such as a Windows timer) is unavailable. const int JOYERR_UNPLUGGED = 167; // The specified joystick is not connected to the system. const int JOY_RETURNX = 0x001; const int JOY_RETURNY = 0x002; const int JOY_RETURNZ = 0x004; const int JOY_RETURNR = 0x008; const int JOY_RETURNU = 0x010; const int JOY_RETURNV = 0x020; const int JOY_RETURNPOV = 0x040; const int JOY_RETURNBUTTONS = 0x080; const int JOY_RETURNALL = 0x0FF; const int JOY_RETURNRAWDATA = 0x100; const int JOY_RETURNPOVCTS = 0x200; const int JOY_RETURNCENTERED = 0x400; [StructLayout(LayoutKind.Sequential)] private struct JOYINFOEX { public int dwSize; public int dwFlags; public int dwXpos; public int dwYpos; public int dwZpos; public int dwRpos; public int dwUpos; public int dwVpos; public int dwButtons; public int dwButtonNumber; public int dwPOV; public int dwReserved1; public int dwReserved2; } MyMessageFilter messageFilter; GamePadTest() { Text = "GamePadTest"; ClientSize = new Size(300, 300); var btnDevNum = new Button(){ Location = new Point(0, 0), Size = new Size(200, 30), Text = "Call joyGetNumDevs", }; btnDevNum.Click += (s,e)=>{ int n = NativeMethods.joyGetNumDevs(); Console.Write("joyGetNumDevs:"); Console.WriteLine(n); }; Controls.Add(btnDevNum); var btnDevPos = new Button(){ Location = new Point(0, 60), Size = new Size(200, 30), Text = "Call joyGetPosEx", }; btnDevPos.Click += (s,e)=>{ var joyInfo = new JOYINFOEX(); joyInfo.dwSize = Marshal.SizeOf(joyInfo); joyInfo.dwFlags = JOY_RETURNALL; int mmresultCode = NativeMethods.joyGetPosEx(JOYSTICKID1, ref joyInfo); Console.Write("joyGetPosEx:"); Console.WriteLine(mmresultCode); Console.Write("dwButtons:0x"); Console.WriteLine(joyInfo.dwButtons.ToString("X8")); }; Controls.Add(btnDevPos); Load += (s,e)=>{ messageFilter = new MyMessageFilter(); Application.AddMessageFilter(messageFilter); NativeMethods.joySetCapture(this.Handle, JOYSTICKID1, 50, 1); }; Closed += (s,e)=>{ NativeMethods.joyReleaseCapture(JOYSTICKID1); }; } [STAThread] static void Main(string[] args) { Application.Run(new GamePadTest()); } }実行結果
十字キーとかボタンを色々押してみた結果
Message:0x3A0 buttons:0x00000000 x:32511 y:32511 Message:0x3A0 buttons:0x00000000 x:32511 y:65535 Message:0x3A0 buttons:0x00000000 x:32511 y:32511 Message:0x3A0 buttons:0x00000000 x:65535 y:32511 Message:0x3A0 buttons:0x00000000 x:32511 y:32511 Message:0x3A0 buttons:0x00000000 x:32511 y:0 Message:0x3A0 buttons:0x00000000 x:32511 y:32511 Message:0x3A0 buttons:0x00000000 x:0 y:32511 Message:0x3A0 buttons:0x00000000 x:32511 y:32511 Message:0x3B5 buttons:0x00000101 x:32511 y:32511 Message:0x3B7 buttons:0x00000100 x:32511 y:32511 Message:0x3B5 buttons:0x00000202 x:32511 y:32511 Message:0x3B7 buttons:0x00000200 x:32511 y:32511 Message:0x3B5 buttons:0x00000808 x:32511 y:32511 Message:0x3B7 buttons:0x00000800 x:32511 y:32511 Message:0x3B5 buttons:0x00000404 x:32511 y:32511 Message:0x3B7 buttons:0x00000400 x:32511 y:32511 joyGetNumDevs:16 joyGetPosEx:0 dwButtons:0x00000000ソースコード その2 - SendInputと組み合わせてマウスを動かす
※使用するデバイス(GamePad)に依存します。GamePadを操作したときにどういう入力が入るかを確認して適宜修正してみてください。
joySetCapture
の最後の引数を0にすることで、ポーリング式で定期的にイベントを発生させます。using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.Drawing; using System.IO; using System.Reflection; using System.Runtime.InteropServices; using System.Windows.Forms; class GamePadTest : Form { class MyMessageFilter : IMessageFilter { const int MM_JOY1MOVE = 0x3A0;// Joystick JOYSTICKID1 changed position in the x- or y-direction. const int MM_JOY2MOVE = 0x3A1;// Joystick JOYSTICKID2 changed position in the x- or y-direction const int MM_JOY1ZMOVE = 0x3A2;// Joystick JOYSTICKID1 changed position in the z-direction. const int MM_JOY2ZMOVE = 0x3A3;// Joystick JOYSTICKID2 changed position in the z-direction. const int MM_JOY1BUTTONDOWN = 0x3B5;// A button on joystick JOYSTICKID1 has been pressed. const int MM_JOY2BUTTONDOWN = 0x3B6;// A button on joystick JOYSTICKID2 has been pressed. const int MM_JOY1BUTTONUP = 0x3B7;// A button on joystick JOYSTICKID1 has been released. const int MM_JOY2BUTTONUP = 0x3B8;// A button on joystick JOYSTICKID2 has been released. // https://docs.microsoft.com/en-us/windows/win32/multimedia/mm-joy1buttondown Control _parent; int _leftThre; int _rightThre; int _upThre; int _downThre; public MyMessageFilter(Control parent, int leftThre, int rightThre, int upThre, int downThre) { _parent = parent; _leftThre = leftThre; _rightThre = rightThre; _upThre = upThre; _downThre = downThre; } public bool PreFilterMessage(ref Message m) { //m.Msg == MM_JOY1BUTTONDOWN // || m.Msg == MM_JOY1BUTTONUP if (m.Msg == MM_JOY1MOVE) { ulong tmp = (ulong)m.LParam; // 64bit環境で31bit目が1のIntPtrをuintにキャストするとOverflowExceptionが発生するっぽい???ので対策。 int xPos = (int)( tmp &0xFFFF); int yPos = (int)((tmp>>16)&0xFFFF); int dX = 0; int dY = 0; if (xPos <= _leftThre) { dX = -5; } else if (xPos >= _rightThre) { dX = 5; } if (yPos <= _upThre) { dY = -5; } else if (yPos >= _downThre) { dY = 5; } _parent.BeginInvoke( (MethodInvoker)delegate(){ SendInputUtil.SendInputMouseRelativeMove(dX, dY); } ); } return false; } } private static class NativeMethods { [DllImport("winmm.dll")] public static extern int joyGetNumDevs(); [DllImport("winmm.dll")] public static extern int joyGetPosEx(int uJoyID, ref JOYINFOEX pji); // hwnd ... Handle to the window to receive the joystick messages. // uJoyID ... Identifier of the joystick to be captured. Valid values for uJoyID range from zero (JOYSTICKID1) to 15. // uPeriod ... Polling frequency, in milliseconds. // fChanged ... Change position flag. Specify TRUE for this parameter to send messages only when the position changes by a value greater than the joystick movement threshold. Otherwise, messages are sent at the polling frequency specified in uPeriod. [DllImport("winmm.dll")] public static extern int joySetCapture(IntPtr hwnd, int uJoyID, int uPeriod, int fChanged); [DllImport("winmm.dll")] public static extern int joyReleaseCapture(int uJoyID); } const int JOYSTICKID1 = 0; const int MMSYSERR_BADDEVICEID = 2; // The specified joystick identifier is invalid. const int MMSYSERR_NODRIVER = 6; // The joystick driver is not present. const int MMSYSERR_INVALPARAM = 11; // An invalid parameter was passed. const int JOYERR_PARMS = 165; // The specified joystick identifier is invalid. const int JOYERR_NOCANDO = 166; // Cannot capture joystick input because a required service (such as a Windows timer) is unavailable. const int JOYERR_UNPLUGGED = 167; // The specified joystick is not connected to the system. const int JOY_RETURNX = 0x001; const int JOY_RETURNY = 0x002; const int JOY_RETURNZ = 0x004; const int JOY_RETURNR = 0x008; const int JOY_RETURNU = 0x010; const int JOY_RETURNV = 0x020; const int JOY_RETURNPOV = 0x040; const int JOY_RETURNBUTTONS = 0x080; const int JOY_RETURNALL = 0x0FF; const int JOY_RETURNRAWDATA = 0x100; const int JOY_RETURNPOVCTS = 0x200; const int JOY_RETURNCENTERED = 0x400; [StructLayout(LayoutKind.Sequential)] private struct JOYINFOEX { public int dwSize; public int dwFlags; public int dwXpos; public int dwYpos; public int dwZpos; public int dwRpos; public int dwUpos; public int dwVpos; public int dwButtons; public int dwButtonNumber; public int dwPOV; public int dwReserved1; public int dwReserved2; } MyMessageFilter messageFilter; GamePadTest() { Text = "GamePadTest"; ClientSize = new Size(300, 300); var btnDevNum = new Button(){ Location = new Point(0, 0), Size = new Size(200, 30), Text = "Call joyGetNumDevs", }; btnDevNum.Click += (s,e)=>{ int n = NativeMethods.joyGetNumDevs(); Console.Write("joyGetNumDevs:"); Console.WriteLine(n); }; Controls.Add(btnDevNum); var btnDevPos = new Button(){ Location = new Point(0, 60), Size = new Size(200, 30), Text = "Call joyGetPosEx", }; btnDevPos.Click += (s,e)=>{ var joyInfo = new JOYINFOEX(); joyInfo.dwSize = Marshal.SizeOf(joyInfo); joyInfo.dwFlags = JOY_RETURNALL; int mmresultCode = NativeMethods.joyGetPosEx(JOYSTICKID1, ref joyInfo); Console.Write("joyGetPosEx:"); Console.WriteLine(mmresultCode); Console.Write("dwButtons:0x"); Console.WriteLine(joyInfo.dwButtons.ToString("X8")); }; Controls.Add(btnDevPos); Load += (s,e)=>{ messageFilter = new MyMessageFilter(this,0,65535,0,65535); Application.AddMessageFilter(messageFilter); int mmResultCode = NativeMethods.joySetCapture(this.Handle, JOYSTICKID1, 50, 0); Console.WriteLine(mmResultCode); }; Closed += (s,e)=>{ NativeMethods.joyReleaseCapture(JOYSTICKID1); }; } [STAThread] static void Main(string[] args) { Application.Run(new GamePadTest()); } } public static class SendInputUtil { private static class NativeMethods { [DllImport("user32.dll", SetLastError = true)] public extern static void SendInput(int nInputs, Input[] pInputs, int cbsize); } private const int WM_MOUSEMOVE = 0x0200; private const int WM_LBUTTONDOWN = 0x0201; private const int WM_LBUTTONUP = 0x0202; private const int WM_RBUTTONDOWN = 0x0204; private const int MOUSEEVENTF_MOVE = 0x0001; private const int MOUSEEVENTF_LEFTDOWN = 0x0002; private const int MOUSEEVENTF_LEFTUP = 0x0004; private const int MOUSEEVENTF_VIRTUALDESK = 0x4000; private const int MOUSEEVENTF_ABSOLUTE = 0x8000; [StructLayout(LayoutKind.Sequential)] struct MouseInput { public int X; public int Y; public int Data; public int Flags; public int Time; public IntPtr ExtraInfo; } [StructLayout(LayoutKind.Sequential)] struct KeyboardInput { public short VirtualKey; public short ScanCode; public int Flags; public int Time; public IntPtr ExtraInfo; } [StructLayout(LayoutKind.Sequential)] struct HardwareInput { public int uMsg; public short wParamL; public short wParamH; } [StructLayout(LayoutKind.Sequential)] struct Input { public int Type; public InputUnion ui; } [StructLayout(LayoutKind.Explicit)] struct InputUnion { [FieldOffset(0)] public MouseInput Mouse; [FieldOffset(0)] public KeyboardInput Keyboard; [FieldOffset(0)] public HardwareInput Hardware; } public static void SendInputMouseRelativeMove(int dX, int dY) { var t = new Input(); t.Type = 0; // MOUSE = 0 t.ui.Mouse.X = dX; t.ui.Mouse.Y = dY; t.ui.Mouse.Data = 0; t.ui.Mouse.Flags = MOUSEEVENTF_MOVE; t.ui.Mouse.Time = 0; t.ui.Mouse.ExtraInfo = IntPtr.Zero; Input[] inputs = new Input[]{t}; NativeMethods.SendInput(inputs.Length, inputs, Marshal.SizeOf(inputs[0])); } }環境
Windows10 64bit.
使用したデバイス:ELECOM JC-U2410TBK
参考サイト
- 投稿日:2020-08-17T02:13:42+09:00
【.NET】 私、 [対象プラットフォーム] は [Any CPU] でって言ったよね!
記事のタイトルに深い意味はありません。
そんな感じのタイトルの作品があったなぁと思って。
概要
先日C#で簡単なツールを作っていたら、
WOW64
のファイル システム リダイレクト
がかかっていた。Any CPU
でコンパイルしているはずなのに、とタスク マネージャーを見たら、おいおい32bit プロセス
で動いているじゃねぇかFxxxxxck!設定
プロジェクトの
プロパティ
のビルド
より32bitを選ぶ
のチェックを外す。
(Visual Studo 20019の場合)効果
言わずもがな、Java や CLR などのVM型実行環境って そもそも
Any CPU
にこそ真価が有ると思うのだが。。。
- Any CPUで動く。
- x86版 Windows では32bitで動く。
- x86_64版 Windows では64bitで動く。
⇒ フォルダ リダイレクトがかからなくる。
⇒ 無計画にP/Invoke
するとBadImageException
で死にやすい。
(無計画が悪い。。。)
これ何のための設定?
対象プラットフォーム
にはAny CPU
でビルドしてるのに、
x86_64版 Windows
上でも32bit プログラム
として動かしたいってこと? なんで????![]()
x86_64版 Windows
でもx86_64 モード
よりx86 モード
のプログラムの方が早い事が多いとか、そんな話?
(x86_64
CPU には 実行モードを切り替えるコンテキスト スイッチ
があり、 Windowsではプロセス単位で切り替えに対応し、 ネイティブ コード で実行させていたと思った。)AArch64
にも 32bit モードがあるらしいので、ARM CPU
も見据えた設定?![]()
Visual Studio 20013から設定はあった様だけど、とりあえず全然意味が分からない。。。
(追記)
- -platform (C# コンパイラ オプション) | Microsoft Docs
https://docs.microsoft.com/ja-jp/dotnet/csharp/language-reference/compiler-options/platform-compiler-optionこういうこと?
arm版やia64版なんて持っていないからわからないけど。
(x86_64のx86モードを良しとするなら、ia64版やarm版 Windowsのx86エミューレーションも効いたりするのかな?)
platform:anycpu32bitpreferred
のARMがやっぱポイントなのかな?参考
-platform (C# コンパイラ オプション) | Microsoft Docs
https://docs.microsoft.com/ja-jp/dotnet/csharp/language-reference/compiler-options/platform-compiler-option.net — Visual Studioの "Any CPU"ターゲットとはどういう意味ですか?
https://www.it-swarm.dev/ja/.net/visual-studio%E3%81%AE-any-cpu%E3%82%BF%E3%83%BC%E3%82%B2%E3%83%83%E3%83%88%E3%81%A8%E3%81%AF%E3%81%A9%E3%81%86%E3%81%84%E3%81%86%E6%84%8F%E5%91%B3%E3%81%A7%E3%81%99%E3%81%8B%EF%BC%9F/958269106/CLR via C# - Jeffrey Richter - Google ブックス
https://books.google.co.uk/books?id=36tCAwAAQBAJ&pg=PT38#v=onepage&q&f=falseVisual Studioの[32ビット優先]設定の目的は何ですか、また実際にはどのように機能しますか?
https://qastack.jp/programming/12066638/what-is-the-purpose-of-the-prefer-32-bit-setting-in-visual-studio-and-how-doesWhat AnyCPU Really Means As Of .NET 4.5 and Visual Studio 11 - DZone IoT
https://dzone.com/articles/what-anycpu-really-means-netVisual Studio 11 と .NET 4.5 で Microsoft が AnyCPU を再定義
https://www.infoq.com/jp/news/2012/04/anycpu_vs11/