GoogleReaderでRSSのチェックをしていたらどう書く?のフィードが更新されたので、以前書いたコードを引っ張り出してちょちょいと手を加えてカカッと投稿。
真の一番乗りゲットォ!
GoogleReaderでRSSのチェックをしていたらどう書く?のフィードが更新されたので、以前書いたコードを引っ張り出してちょちょいと手を加えてカカッと投稿。
真の一番乗りゲットォ!
パスワード入力用のテキストボックスで、入力しても”******”としか表示されないものがありますよね。あれ、不便ですよね。自分で入力したのに見えないなんて理不尽ですよね。
そこで、無理やり入力内容が見える様にするプログラムを書いてみました。Vector辺りを探せばあるような気がするけど気にしたら負けでしょう。
実はアレ、ただのテキストボックスなのでメッセージ投げれば好きなように弄れちゃうんですよね。で、今回投げたのはEM_SETPASSWORDCHAR。EnumChildWindows関数でウィンドウを列挙して手当たり次第にPostMessageしてます。
はい、コードです。
using System; using System.Runtime.InteropServices; namespace ConsoleApplication1 { class Program { const int EM_SETPASSWORDCHAR = 0xCC; delegate int WNDENUMPROC(IntPtr hwnd, int lParam); [DllImport("user32.dll")] private static extern int EnumChildWindows( IntPtr hWndParent, WNDENUMPROC lpEnumFunc, int lParam); [DllImport("user32.dll")] private static extern int PostMessage( IntPtr hwnd, int wMsg, int wParam, int lParam); static void Main(string[] args) { EnumChildWindows(IntPtr.Zero, EnumWindowsProc, 0); } static int EnumWindowsProc(IntPtr hWndParent, int lParam) { PostMessage(hWndParent, EM_SETPASSWORDCHAR, 0, 0); EnumChildWindows(hWndParent, EnumWindowsProc, 0); return 1; } } }
これでパスワード丸見えなんですってば。
TTBase http://ttbase.sourceforge.jp/
逆P/Invoke http://www.artonx.org/diary/20081124.html#p01
これでC#でTTBaseのプラグイン作れるんじゃね?と思った。
TTBase.cs TTBaseで使用する構造体とか定数とか
using System; using System.Runtime.InteropServices; namespace TTBasePlugInTest { //プラグインのロードタイプ public enum LoadType { ptAlwayLoad = 0, ptLoadAtUse = 1, ptSpecViolation = 0xFFFF } //メニューに関する定数 public enum Menu { dmNone = 0, dmSystemMenu = 1, dmToolMenu = 2, dmHotKeyMenu = 4, dmMenuChecked = 8 } public enum LogOut { elNever = 0, elError = 1, elWarning = 2, elInfo = 3, elDebug = 4 } [StructLayout(LayoutKind.Sequential,CharSet = CharSet.Ansi)] public struct PLUGIN_COMMAND_INFO { [MarshalAs(UnmanagedType.LPStr)] public string Name; [MarshalAs(UnmanagedType.LPStr)] public string Caption; public int CommandID; public int Attr; public int ResID; public int DispMenu; public uint TimerInterval; public uint TimerCounter; } [StructLayout(LayoutKind.Sequential,CharSet= CharSet.Ansi)] public struct PLUGIN_INFO { public ushort NeedVersion; [MarshalAs(UnmanagedType.LPStr)] public string Name; [MarshalAs(UnmanagedType.LPStr)] public string FileName; public ushort PluginType; public uint VersionMS; public uint VersionLS; public uint CommandCount; [MarshalAs(UnmanagedType.LPStruct)] public IntPtr Commands; //public PLUGIN_COMMAND_INFO Commands; public uint LoadTime; } }
Class1.cs TTBaseに公開するメソッドを実装
using System; using System.Runtime.InteropServices; namespace TTBasePlugInTest { public class Class1 { public static IntPtr TTBEVent_InitPluginInfo(string PluginFilename) { PLUGIN_INFO r = new PLUGIN_INFO(); r.FileName = PluginFilename; r.NeedVersion = 0; r.Name = "テスト"; r.PluginType = (int)LoadType.ptAlwayLoad; r.CommandCount = 1; PLUGIN_COMMAND_INFO pci = new PLUGIN_COMMAND_INFO(); pci.Name = "test"; pci.Caption = "てすてす、テストのテストです"; pci.CommandID = 0; pci.DispMenu = (int)(Menu.dmToolMenu | Menu.dmHotKeyMenu); IntPtr pciPtr = Marshal.AllocHGlobal(Marshal.SizeOf(pci)); Marshal.StructureToPtr(pci, pciPtr, false); r.Commands = pciPtr; //r.Commands = pci; IntPtr iPtr = Marshal.AllocHGlobal(Marshal.SizeOf(r)); Marshal.StructureToPtr(r, iPtr, false); return iPtr; } public static void TTBEvent_FreePluginInfo(IntPtr PluginInfo) { Marshal.FreeHGlobal(PluginInfo); } public static int TTBEvent_Init(string PluginFilename, int hPlugin) { return 1; } public static void TTBEvent_Unload() { } static int i; public static int TTBEvent_Execute(int CommandID, IntPtr hWnd) { i++; System.Windows.Forms.MessageBox.Show(i.ToString()); return 1; } public static void TTBEvent_WindowsHook(int Msg, int wParam, int lParam) { } } }
上のコードをビルドしたら
D:\My Documents\Visual Studio 2008\Projects\TTBasePlugInTest\TTBasePlugInTest\bi
n\Release>ildasm /OUT=TTBasePlugInTest.il TTBasePlugInTest.dll
でILにする。
逆P/Invokeを参考にILを編集
D:\My Documents\Visual Studio 2008\Projects\TTBasePlugInTest\TTBasePlugInTest\bi
n\Release>c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\ilasm.exe /DLL TTBasePlu
gInTest.il
Microsoft (R) .NET Framework IL Assembler. Version 2.0.50727.3053
Copyright (c) Microsoft Corporation. All rights reserved.
Assembling 'TTBasePlugInTest.il' to DLL --> 'TTBasePlugInTest.dll'
Source file is ANSI
Assembled method TTBasePlugInTest.Class1::TTBEVent_InitPluginInfo
Assembled method TTBasePlugInTest.Class1::TTBEvent_FreePluginInfo
Assembled method TTBasePlugInTest.Class1::TTBEvent_Init
Assembled method TTBasePlugInTest.Class1::TTBEvent_Unload
Assembled method TTBasePlugInTest.Class1::TTBEvent_Execute
Assembled method TTBasePlugInTest.Class1::TTBEvent_WindowsHook
Assembled method TTBasePlugInTest.Class1::.ctor
Creating PE file
Emitting classes:
Class 1: TTBasePlugInTest.Class1
Class 2: TTBasePlugInTest.PLUGIN_INFO
Class 3: TTBasePlugInTest.PLUGIN_COMMAND_INFO
Class 4: TTBasePlugInTest.LoadType
Class 5: TTBasePlugInTest.Menu
Class 6: TTBasePlugInTest.LogOut
Emitting fields and methods:
Global
Class 1 Fields: 1; Methods: 7;
Class 2 Fields: 9;
Class 3 Fields: 8;
Class 4 Fields: 4;
Class 5 Fields: 6;
Class 6 Fields: 6;
Resolving local member refs: 13 -> 13 defs, 0 refs, 0 unresolved
Emitting events and properties:
Global
Class 1
Class 2
Class 3
Class 4
Class 5
Class 6
Resolving local member refs: 0 -> 0 defs, 0 refs, 0 unresolved
Writing PE file
Operation completed successfully
とILからDLLを作成。メッセージの意味はよくわからないけど、多分成功してる。
これで出来たDLLをTTBaseのディレクトリにコピーしてTTBaseを起動するも…プラグインとして認識されない。
どこが上手く行ってないのかもわからない状態。
http://twitter.com/takeshik/statuses/2419234928
とか言われたけどC++/CLIとかキモいし。
http://twitter.com/takeshik/statuses/2419254967
とか突っ込まれたけどその通りだと思う。
C#でやることに意味があるのですよ。C#可愛いよ、C#可愛い。
でもC#で出来て無いから何の意味も無いという…。
PropertyGridコントロールに表示されるプロパティ名を変更するには?
SPDVer 1.74に取り込み完了。
とメモしておけば万一上記リンクが切れてもSPDVer 1.74のコードからサルベージ可能。あにすのコード保管庫に転載するわけにもいかないしね。
あにすのコード保管庫はあにすが書いたコードの保管庫だけど、あにすが書いてないコードも保管したいな。何か良い方法は無いだろうか。公開ブックマーク的なものがあればいいのかな。
[C#]ユーザーコントロールをドラッグアンドドロップで移動で面白そうなことやってるので書いてみました。結構泥臭くなりますね。ちょっと嵌ってしまって時間が掛かったのはここだけの秘密。
using System.Drawing; using System.Windows.Forms; public partial class UserControl1 :UserControl { Size lastMouseDownSize; Point lastMouseDownPoint; DAndDStatus status; int sizeChangeArea = 8; public UserControl1() { InitializeComponent(); } protected override void OnMouseDown(MouseEventArgs e) { lastMouseDownPoint = e.Location; lastMouseDownSize = this.Size; //動作を決定 status = DAndDStatus.None; if(getTop().Contains(e.Location)) { status |= DAndDStatus.Top; } if(getLeft().Contains(e.Location)) { status |= DAndDStatus.Left; } if(getBottom().Contains(e.Location)) { status |= DAndDStatus.Bottom; } if(getRight().Contains(e.Location)) { status |= DAndDStatus.Right; } if(status == DAndDStatus.None) { status = DAndDStatus.Move; } else { this.Capture = true; } base.OnMouseDown(e); } protected override void OnMouseMove(MouseEventArgs e) { //カーソルを変更 if((getTop().Contains(e.Location) && getLeft().Contains(e.Location)) || (getBottom().Contains(e.Location) && getRight().Contains(e.Location))) { this.Cursor = Cursors.SizeNWSE; } else if((getTop().Contains(e.Location) && getRight().Contains(e.Location)) || (getBottom().Contains(e.Location) && getLeft().Contains(e.Location))) { this.Cursor = Cursors.SizeNESW; } else if(getTop().Contains(e.Location) || getBottom().Contains(e.Location)) { this.Cursor = Cursors.SizeNS; } else if(getLeft().Contains(e.Location) || getRight().Contains(e.Location)) { this.Cursor = Cursors.SizeWE; } else { this.Cursor = Cursors.Default; } if(e.Button == MouseButtons.Left) { int diffX = e.X - lastMouseDownPoint.X; int diffY = e.Y - lastMouseDownPoint.Y; if((status & DAndDStatus.Move) == DAndDStatus.Move) { this.Left += diffX; this.Top += diffY; } if((status & DAndDStatus.Top) == DAndDStatus.Top) { int h = this.Height; this.Height -= diffY; this.Top += h - this.Height; } if((status & DAndDStatus.Bottom) == DAndDStatus.Bottom) { this.Height = lastMouseDownSize.Height + diffY; } if((status & DAndDStatus.Left) == DAndDStatus.Left) { int w = this.Width; this.Width -= diffX; this.Left += w - this.Width; } if((status & DAndDStatus.Right) == DAndDStatus.Right) { this.Width = lastMouseDownSize.Width + diffX; } } this.Refresh(); base.OnMouseMove(e); } protected override void OnMouseUp(MouseEventArgs e) { this.Capture = false; base.OnMouseUp(e); } protected override void OnPaint(PaintEventArgs e) { e.Graphics.DrawRectangle( Pens.Black, 0, 0, this.Width - 1, this.Height - 1); base.OnPaint(e); } private Rectangle getTop() { return new Rectangle(0, 0, this.Width, sizeChangeArea); } private Rectangle getBottom() { return new Rectangle(0, this.Height - sizeChangeArea, this.Width, sizeChangeArea); } private Rectangle getLeft() { return new Rectangle(0,0, sizeChangeArea, this.Height); } private Rectangle getRight() { return new Rectangle(this.Width - sizeChangeArea, 0, sizeChangeArea, this.Height); } private enum DAndDStatus { None = 0, Move = 1, Top = 2, Bottom = 4, Left = 8, Right = 16, } }
TextBoxコントロール上でのドラッグ&ドロップでフォームを移動させようとした場合、文字列を選択する操作とバッティングしないようにする必要がある。
以下の実装で良い感じに動いた。
Point mouseDownPoint = new Point(); bool dAndDMoveFlag = false; private void textBox1_MouseDown(object sender, MouseEventArgs e) { if(e.Button != MouseButtons.Left) return; mouseDownPoint = e.Location; bool flag = true; int charHeight = TextRenderer.MeasureText("A", this.textBox1.Font).Height; for(int i = 0; i < this.textBox1.Lines.Length; i++) { Point point = new Point(0, i * charHeight); Size size = TextRenderer.MeasureText( this.textBox1.Lines[i], this.textBox1.Font); Rectangle rect = new Rectangle(point, size); if(rect.Contains(e.Location)) { flag = false; break; } } this.dAndDMoveFlag = flag; } private void textBox1_MouseMove(object sender, MouseEventArgs e) { if(dAndDMoveFlag) { Point p = this.Location; p.Offset( new Point(e.X - mouseDownPoint.X, e.Y - mouseDownPoint.Y)); this.Location = p; } } private void textBox1_MouseUp(object sender, MouseEventArgs e) { dAndDMoveFlag = false; }
素早くドラッグ&ドロップしたときに文字が選択されてしまいフォームの移動がキャンセルされるのを回避する為にdAndDMoveFlag(センスねー名前w)でフラグを立てている。
あとはそんなに難しいことしてないと思う。
※textBox1のTextが空の場合にLinesプロパティの境界外を参照して例外が発生していたので修正した。
※気が変わったので違うロジックでゴッソリと書き換えた。
Enumerable.Range(1, 100).Select<int, string>(i => (i % 15 == 0 ? “FizzBuzz” : (i % 3 == 0 ? “Fizz” : (i % 5 == 0 ? “Buzz” : i.ToString())))).ToList<string>().ForEach(s => { Console.WriteLine(s); });
反省している。
http://www.voidspace.org.uk/ironpython/ip_in_ip.shtml (英語)
英語は読めないからソースだけ読んで参考にしました。
【参照設定】
IronPython2.0のディレクトリより
IronPython.dll
Microsoft.Scripting.Core.dll
Microsoft.Scripting.dll
【Form1.cs】
using System;
using System.Windows.Forms;
using IronPython.Hosting;
using Microsoft.Scripting.Hosting;
public partial class Form1 :Form {
public Form1() {
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e) {
ScriptEngine engine = Python.CreateEngine();
ScriptSource source =
engine.CreateScriptSourceFromFile(“./test.py”);
ScriptScope scope = engine.CreateScope();
//IronPythonにformという変数名でthisを渡す。
scope.SetVariable(“form”, this);
//ここで実行
source.Execute(scope);
//IronPythonのtestVarという変数のオブジェクトを取得する。
object value = scope.GetVariable(“testVar”);
this.button1.Text = (string)value;
}
}
【test.py】
form.Text = “Hello,World!”
testVar = “test”
こんな感じで、IronPython側にオブジェクトを渡してIronPython側で操作したり、IronPython側のオブジェクトをC#側で取得することが出来ました。
IronPythonとのオブジェクトのやり取りはScriptScopeオブジェクトを通して行うんですね。
これだけでもかなり面白いです。IronPython1.0からはかなり勝手が変わったようです。
C/Migemoをダウンロードしたら、toolsフォルダにMigemo.csというラッパーがあります。
GetRegexメソッドを叩けばRegexクラスのオブジェクトが返ります。