今日のびっくり。
‘System.Text.Encoding.GetString(byte[])’ はアクセスできない保護レベルになっています。
Encoding.UTF8.GetString(data);
こんなコードを書くとビルド時エラーになります。
なぜか、Encoding.GetString(Byte[], Int32, Int32)は使えます。
Encoding.UTF8.GetString(data, 0, data.Length);
こうしておけばOK。何だろう、この仕様。
2010/01/28
今日のびっくり。
‘System.Text.Encoding.GetString(byte[])’ はアクセスできない保護レベルになっています。
Encoding.UTF8.GetString(data);
こんなコードを書くとビルド時エラーになります。
なぜか、Encoding.GetString(Byte[], Int32, Int32)は使えます。
Encoding.UTF8.GetString(data, 0, data.Length);
こうしておけばOK。何だろう、この仕様。
2010/01/28
コントロールはひとつの case ラベル (‘default:’) から別のラベルへ流れ落ちることはできません。
switch (message)
{
case "hoge":
funcA();
break;
default:
funcB();
break; // これがないとエラー
}
他の言語のクセでbreak書かなかったら起きた。
「フォールスルー」ってことなんですね。
ちなみにcaseのあとのブロックにコードを書かなければフォールスルーはできるという話。
2010/01/27
private void Form1_Load(object sender, EventArgs e)
{
string html = @"<!DOCTYPE html PUBLIC ""-//W3C//DTD XHTML 1.0 Transitional//EN"" ""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"">
<!-- saved from url=(0014)about:internet -->
<html xmlns=""http://www.w3.org/1999/xhtml"" >
<head>
<title>Test</title>
<script type=""text/xaml"" id=""testXaml"">
<?xml version=""1.0""?>
<Canvas xmlns=""http://schemas.microsoft.com/client/2007"">
<Ellipse Fill=""Pink"" Width=""200"" Height=""100"" Canvas.Left=""40"" Canvas.Top=""30"" />
<Rectangle Fill=""Orange"" Width=""100"" Height=""160"" Canvas.Left=""150"" Canvas.Top=""50"" />
<TextBlock Text=""This is text on Silverlight"" Canvas.Left=""10"" Canvas.Top=""150"">
<TextBlock.RenderTransform>
<RotateTransform Angle=""-30"" />
</TextBlock.RenderTransform>
</TextBlock>
</Canvas>
</script>
</head>
<body>
<object type=""application/x-silverlight-2"" width=""800"" height=""600"">
<param name=""source"" value=""#testXaml""/>
</object>
</body>
</html>";
if (webBrowser1.Document == null)
{
webBrowser1.Navigate("about:blank");
}
webBrowser1.Document.OpenNew(true);
webBrowser1.Document.Write(html);
}
結果
XAMLソースはこちらから拝借。
【コラム】The Silverlight Times (16) 覚えておきたい「インラインXAML」 | ネット | マイコミジャーナル
WebBrowserの使い方はこちらを参考にしました。
WebBrowserコントロールのコンテンツを文字列により設定するには?[2.0、C#、VB] - @IT
2009/09/10
今までFiddlerをただのセッションの中身を確認できるLocal Proxyとしてしか見ていなかったのですが
改めて良く調べると色々できることが多すぎると判明。感動したので便利な機能をまとめてみました。
先に簡単に説明しておくと、FiddlerはMicrosoftが無料で配布しているWeb Debugging Proxyです。
Windows環境にインストールして、ブラウザとサーバの間の通信を読んだり操作したりできます。
配布サイトはこちら。
Fiddler Web Debugger – A free web debugging tool
動作環境は「Windows 2000 / XP / 2003 / Vista with Microsoft .NET Framework v2.0 or later」
今回使ったバージョンは、2009年9月10日時点で最新の安定版、2.2.4.6。
とりあえず簡単に目次。
マークアップエンジニアにおすすめしたいのは
あたり。
プログラマには全部おすすめ。
詳細は「続き」からどうぞ。
2009/09/09
常駐アプリケーションを作ったはいいが、アンインストールしようとしたときにプロセスが起動していると、削除できなくて困る。
というわけで、プロセスを殺す目的のプラグインDLLを作成。コンパイル済みファイルはエントリの最後に。
taskkillコマンド使えという話ですが、Windows XP Home Editionにはtaskkillコマンドが含まれていないので。
今回もさっくりC#で。C#.NETで作ってしまうと、そのままではNSISで使えないのだけど、.NETで作ったDLLをNSISのプラグインとして使う方法は以下のエントリを参照。
NSISで、C#で書かれた自作のDLLを使う : blog.loadlimit – digital matter –
ソースは以下。C#でクラスライブラリとしてプロジェクトを作成。プロセス名を指定すると、マッチしたプロセスを全部終了してくれます。
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace TaskKill
{
public class TaskKill
{
[DllImport("Psapi.dll", SetLastError = true)]
static extern bool EnumProcesses(
[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.U4)] [In][Out] UInt32[] processIds,
UInt32 arraySizeBytes,
[MarshalAs(UnmanagedType.U4)] out UInt32 bytesCopied
);
[DllImport("kernel32.dll")]
static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle,
uint dwProcessId);
[Flags]
public enum ProcessAccessFlags : uint
{
All = 0x001F0FFF,
Terminate = 0x00000001,
CreateThread = 0x00000002,
VMOperation = 0x00000008,
VMRead = 0x00000010,
VMWrite = 0x00000020,
DupHandle = 0x00000040,
SetInformation = 0x00000200,
QueryInformation = 0x00000400,
Synchronize = 0x00100000
}
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CloseHandle(IntPtr hObject);
[StructLayout(LayoutKind.Sequential)]
public struct StringBuffer
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string text;
}
[DllImport("psapi.dll")]
private static extern bool EnumProcessModules(IntPtr hProcess, out IntPtr lphModule, int cb, out int lpcbNeeded);
[DllImport("psapi.dll")]
private static extern int GetModuleBaseName(IntPtr hProcess, IntPtr hModule, out StringBuffer lpBaseName, int nSize);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool TerminateProcess(IntPtr hProcess, int uExitCode);
public static void KillByName(string pname)
{
UInt32 arraySize = 1024;
UInt32 arrayBytesSize = arraySize * sizeof(UInt32);
UInt32[] processIds = new UInt32[arraySize];
UInt32 bytesCopied;
bool success = EnumProcesses(processIds, arrayBytesSize, out bytesCopied);
if (!success)
{
return;
}
if (0 == bytesCopied)
{
return;
}
UInt32 numIdsCopied = bytesCopied >> 2;
if (0 != (bytesCopied & 3))
{
UInt32 partialDwordBytes = bytesCopied & 3;
return;
}
for (UInt32 index = 0; index < numIdsCopied; index++)
{
IntPtr hProcess = OpenProcess(
ProcessAccessFlags.QueryInformation | ProcessAccessFlags.VMRead | ProcessAccessFlags.Terminate,
false,processIds[index]);
if (hProcess.ToInt32() != 0)
{
IntPtr hMod = IntPtr.Zero;
int cbNeeded;
StringBuffer szProcessName;
szProcessName.text = "<unknown>";
if (EnumProcessModules(hProcess, out hMod, Marshal.SizeOf(hMod), out cbNeeded))
{
GetModuleBaseName(hProcess, hMod, out szProcessName, Marshal.SizeOf(szProcessName));
}
if (szProcessName.text == pname)
{
TerminateProcess(hProcess, -1);
}
CloseHandle(hProcess);
}
}
}
}
}
で、これをNSISの配布ファイルに含めておいて、
; アンインストーラ Section "Uninstall" ; アンインストールで使用するプラグインの準備 InitPluginsDir SetOutPath $PLUGINSDIR File "TaskKill.dll" ; hogehoge.exeが起動していたら、それを落とす CLR::Call /NOUNLOAD "TaskKill.dll" "TaskKill.TaskKill" "KillByName" 1 "hogehoge.exe" ; インストールしたファイル群削除 Delete $INSTDIR\*.* CLR::Destroy SectionEnd
という感じでnsiファイルを記述。
ファイルは下記リンクからダウンロードしてお使いください。
2009/08/31
Vistaでソフトウェアキーボードというか、スクリーンキーボードを作ろうとしてハマったのでメモ。ただし、結局解決には至っていません。アプローチ変えてしまったので。
スクリーンキーボードを作るにあたって検索すると、imm32関連の関数を使ったサンプルが諸々出てくるのだけど、どうやらこの関数がWindows XPまでのもので、Vista以降はTSF(Text Services Framework)というものに置き換わっているらしい。
これに気づかず、
IntPtr hIMC = ImmGetContext(AHwnd);
IntPtr hKL = GetKeyboardLayout(0);
int dwSize = ImmGetConversionList(hKL, hIMC, AText, IntPtr.Zero, 0, GCL_CONVERSION);
とかやっていたのだけど、ImmGetConversionListの結果が必ず0になってしまう。
試してないけど、TSFのドキュメントは以下。
Text Services Framework Reference (Windows)
で、ここまでわかったところで、結局Linuxでやることになりました。
2009/08/28
NSISでインストーラ&アンインストーラを作っていて、インストール時に一緒にインストールしたAdobe AIRアプリケーションを、アンインストール時に同時にアンインストールしたいという要件。
Adobe AIRアプリケーションのアンインストールは、手動ならWindowsのコントロールパネルからできるので、ここの情報をレジストリから引っ張り出して実行すればOK。この辺は良くある手段。
で、レジストリからアンインストールに必要なプログラムの実行パス情報を持ってこようとしたら、Adobe AIRでは、Uninstall以下のサブキーの名前が毎回変わるので、検索する必要があることが発覚。
NSISにはレジストリの特定のキーを読む機能はあっても、キーを検索する機能はないので、DLLで拡張を作成。さっくり適当にC#でレジストリを検索して文字列を返すDLLを作成してみた。
ちなみにアンインストール情報はHKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall以下にあります。
ということで、必要な動作はUninstall以下のサブキーを全部開いてDisplayNameが目的の名前と一致するサブキーを探すこと。ソースは以下。
SearchUninstall.cs
using System;
using System.Collections.Generic;
using System.Text;
namespace SearchUninstall
{
public class SearchUninstall
{
public static string Find(string name)
{
string keyPath = "";
// レジストリからの読み取り
Microsoft.Win32.RegistryKey regkey =
Microsoft.Win32.Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall", false);
// キーが存在しないときは null が返される
if (regkey == null) return null;
// 文字列を読み込む
// 読み込む値が存在しないときは null が返される
string stringValue = (string)regkey.GetValue("string");
// sub以下のすべてのキー名を取得
string[] keyNames = regkey.GetSubKeyNames();
foreach (string k in keyNames)
{
string tmp_keyPath = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\" + k;
Microsoft.Win32.RegistryKey regkey2 =
Microsoft.Win32.Registry.LocalMachine.OpenSubKey(tmp_keyPath, false);
try
{
string displayName = (string)regkey2.GetValue("DisplayName");
if (displayName == name)
{
keyPath = tmp_keyPath;
break;
}
}
catch (Exception e)
{
;
}
finally
{
regkey2.Close();
}
}
//閉じる
regkey.Close();
return keyPath;
}
}
}
で、出来上がったDLLをNSISに読み込ませようとしても、どうにも動かない。
Dependency walkerで他のDLLと見比べてみると、C#で作られたDLLはエントリポイントが見えない。
そう言えばそんな話もあったような。
参考:WINAMP.COM | Forums – How can I use a C# DLL in NSIS
NSISからでは.NETのDLLが読めないらしい。ということで、見つけたのが以下。.NETのDLLを使えるようにするプラグイン。
Call .NET DLL methods plug-in – NSIS
CLR.zipをダウンロードしてきて、NSISをインストールしたフォルダのPluginsフォルダに入れておけばOK。
先に作ったSearchUninstall.dllはnsiファイルと同じ場所に入れておく。
で、nsiファイルは以下の感じ。Uninstall部分の必要部分を抜粋。
; アンインストーラ Section "Uninstall" ; アンインストールで使用するプラグインの準備 InitPluginsDir SetOutPath $PLUGINSDIR File "SearchUninstall.dll" ; AIRアプリケーションのアンインストーラを探す CLR::Call /NOUNLOAD "SearchUninstall.dll" "SearchUninstall.SearchUninstall" "Find" 1 "HogeHogeAir" pop $0 CLR::Destroy ReadRegStr $4 HKLM $0 "UninstallString" ; AIRアプリケーションのアンインストーラをPassiveモード(自動処理)で実行する ExecWait "$4 /passive" ; 後片付け Delete "$PLUGINSDIR\SearchUninstall.dll" SectionEnd
これで、アンインストール時にAdobe AIRアプリケーションのアンインストーラも勝手に起動して削除できる。
CLR超便利。プラグインを作るのが相当楽に。