digital matter

‘Windows’ タグのついている投稿

今日の微妙エラー

コントロールはひとつの case ラベル (‘default:’) から別のラベルへ流れ落ちることはできません。

switch (message)
{
    case "hoge":
        funcA();
        break;
    default:
        funcB();
        break; // これがないとエラー
}

他の言語のクセでbreak書かなかったら起きた。

「フォールスルー」ってことなんですね。

ちなみにcaseのあとのブロックにコードを書かなければフォールスルーはできるという話。

Pythonのwin32comからSilverlightを使おうと試みる

最終的にはPythonで書かれたWindowsアプリケーションで、Silverlightのコンテンツをロードしたいという目的なのですが、とりあえずSilverlightのActiveXコントロールを読み込んで動作を確認してみたいので色々実験。

まず、インストールされているSilverlightのバージョンを調べてみる。

Javascriptで書かれたコードがいくつか見つかったのでそれを書き直す。

以下はJS版。

var control = new ActiveXObject('AgControl.AgControl');
alert(control.IsVersionSupported('3.0'));

これをPythonで書いてみる。

import win32com.client
control = win32com.client.Dispatch("AgControl.AgControl")
print control.IsVersionSupported('3.0')

Silverlight 3がインストールされていればTrueが表示されます。

他にどんなメソッドが定義されているのかを調べるために、Visual StudioからAgControlを参照して、オブジェクトブラウザで調査。

というか、Silverlightのプラグインのリファレンスがあった。

Silverlight プラグインのオブジェクト リファレンス

が…Sourceを指定してもIsLoadedプロパティがTrueにならない…うーん…もう少し調べてみる。

PythonでMIDI出力をしてみる

既存のPythonで作ったWindowsアプリケーションにMIDI出力を組み込む用事があったので、実験してみました。

参考サイトはこちら。

sulume blog» ブログアーカイブ » python で MIDI を使う

MIDIIO.dllというのはおーぷんMIDIぷろじぇくとで公開されているMIDIメッセージ入出力用ライブラリです。

これもダウンロードして、pyファイルと同じ場所に置いておきます。

で、ソースコードはこちら。

import ctypes
import time

midiiolib = ctypes.windll.LoadLibrary(r".\MIDIIO.dll")

c_deviceName = ctypes.create_string_buffer(32)

midiiolib.MIDIOut_GetDeviceName(0, c_deviceName, 32)
midiout = midiiolib.MIDIOut_Open(c_deviceName.value)

c_mess = ctypes.create_string_buffer(3)
c_mess.value = '\x90\x3C\x64'

midiiolib.MIDIOut_PutMIDIMessage(midiout, c_mess.value, 3)

time.sleep(3)

midiiolib.MIDIOut_Close(midiout)

説明することもあまりないですが、8行目のMIDIOut_GetDeviceNameで、MIDI出力の先頭のデバイスの名前を先に取得します。

で、その名前を使ってMIDIOut_Openで出力デバイスを開きます。

11~12行目ではノートを作成します。とりあえずドの音でも鳴らしておきます。この辺もMIDIIO.dllに入っていたドキュメントのサンプルと同じ。

あとはMIDIOut_PutMIDIMessageで出力するだけです。

ちゃんと閉じておかないと、次回音が鳴らなかったりする(オープンに失敗します)ので、MIDIOut_Closeで閉じておきましょう。

実験として、ちょっと長いデータを指定してみる。

import ctypes
import time

midiiolib = ctypes.windll.LoadLibrary(r".\MIDIIO.dll")

c_deviceName = ctypes.create_string_buffer(32)

midiiolib.MIDIOut_GetDeviceName(0, c_deviceName, 32)
midiout = midiiolib.MIDIOut_Open(c_deviceName.value)

notes = ['\x90\x3C\x64',
         '\x90\x3E\x64',
         '\x90\x40\x64',
         '\x90\x41\x64',
         '\x90\x43\x64',
         '\x90\x45\x64',
         '\x90\x47\x64',
         '\x90\x48\x64']

c_mess = ctypes.create_string_buffer(3)

for note in notes:
    c_mess.value = note

    midiiolib.MIDIOut_PutMIDIMessage(midiout, c_mess.value, 3)
    time.sleep(0.5)

time.sleep(1.0)

midiiolib.MIDIOut_Close(midiout)

和音を鳴らしてみるテスト。

import ctypes
import time

midiiolib = ctypes.windll.LoadLibrary(r".\MIDIIO.dll")

c_deviceName = ctypes.create_string_buffer(32)

midiiolib.MIDIOut_GetDeviceName(0, c_deviceName, 32)
midiout = midiiolib.MIDIOut_Open(c_deviceName.value)

notes = ['\x90\x3C\x64',
         '\x90\x40\x64',
         '\x90\x43\x64']

c_mess = ctypes.create_string_buffer(3)

for note in notes:
    c_mess.value = note

    midiiolib.MIDIOut_PutMIDIMessage(midiout, c_mess.value, 3)

time.sleep(3.0)

midiiolib.MIDIOut_Close(midiout)

とりあえずこれだけできれば満足なので終了。

ネットワークドライブからデータを全部バックアップする

TeraStationのHDDが1台故障したので、交換を前に中身を全部バックアップする必要がありました。

ちなみに以前同じような症状でRAID崩壊させたことがあるので今回は慎重に…

共有フォルダのルートがたくさんあるので、それをいかに簡単にコピーするかがキモ。

共有フォルダ自体はコピーしようとドラッグアンドドロップすると、ショートカットが作られてしまう。

やりたいことは、PCを使ってLAN内のNASからデータを全部コピーして、ローカルに接続してあるUSB HDDにバックアップすること。

で、robocopyコマンドというのが便利っぽいので使ってみた。使ったOSはWindows Vista。標準コマンド?

まずは対象のフォルダ名一覧の取得から。

C:\> net view \\NAS

みたいにすると、フォルダ一覧が文字情報として取れます。

で、robocopy。

robocopyでフォルダをバックアップ/同期させる - @IT

どうやらrsyncみたいに使えるよう。

C:\> robocopy /mir \\NAS\dir1 C:\Backup\dir1

という感じで書けば対象ディレクトリの中身をミラーリングコピーしてくれます。

ちなみに受け側ディレクトリは作っておかなくても勝手に作ってくれます。

というわけで、先ほどのnet viewの結果を流し込んだコマンドリストを作ってbatファイルに保存して、実行。

全部きれいにバックアップできました。

今xcopyって推奨されてないんですね。知らなかった。

NSISから使える、起動中のプロセスを削除するプラグイン

常駐アプリケーションを作ったはいいが、アンインストールしようとしたときにプロセスが起動していると、削除できなくて困る。

というわけで、プロセスを殺す目的のプラグイン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ファイルを記述。

ファイルは下記リンクからダウンロードしてお使いください。

download TaskKill.dll

スクリーンキーボード

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になってしまう。

imm32 を使ったプログラムの互換性について

試してないけど、TSFのドキュメントは以下。

Text Services Framework Reference (Windows)

で、ここまでわかったところで、結局Linuxでやることになりました。

マウスを動かしただけでCPU使用率が100%に行く現象

Windowsを使っていると、だんだんと重くなってきて、マウスもガクガク飛ぶようになった。うーん?以前はこんなことなかったけどなぁと思って原因究明に乗り出すことに。

使用OSはWindows Vista Ultimate 32bit。半日使ってると重くなってきて、1日経つとまともにブラウザも扱えない。

Core2Quadでメモリ4GBな上、ブラウザしか起動していなくても遅いので、マシンスペック云々ではないことを先に断っておきます。

まぁ、結論から言うとDisplayLink製のUSBモニタが問題でした。というか、それに付随するアプリケーションとサービスか。当該のプロセスは以下の3つ。

  • DisplayLinkUI.exe
  • DisplayLinkService.exe
  • DisplayLinkManager.exe

ServiceとManagerは全ユーザのプロセスを表示で、管理権限にならないと削除できないので注意。

3つ落としてやったら途端に快適な環境が復活しました。これ単体ではさほどCPU食ったりしないので、意外と気づきにくいかも?ちなみに使ってるUSBモニタはSAMSUNGのSyncMaster U70。

OS起動時に2回に1回ブルースクリーンになったり、色々あやしさは感じていたのだけど、ドライバの出来が良くないなぁ…USBサブモニタ流行ってるから、同じような現象が大量発生しているんじゃないかと不安だわ。

調べてみたら、バージョンは4.6.17952.0。付属のCDから一度バージョンアップしてます。

今見たら新しいメジャーバージョン(5.1)出てたので試してみます。この分野は可能性感じるし、U70自体は結構気に入ってるので、早々に安定してくれることを期待。

ダウンロードはこちらから。

DisplayLink: DisplayLink: Windows Drivers

ウィルスバスター2009とか疑ってすまんかった。同じような現象に悩まされている人の一助になれば幸いです。

追記

5.1にしたら遅くなる現象は直った模様。USBモニタ上でのマウスポインタの動作が遅くなったけど、別にクリティカルじゃないのでOK。

Photoshopの強制終了と対応

Photoshop CS3を起動しようとしたら、起動スプラッシュ表示中に突然強制終了する現象に見舞われた。

同じPCに入っているCS2もダメ。

スプラッシュの文字を追っていくと、どうやら「TWAIN メニュー項目を作成」というところで止まっているようだ。

うーん、最近何か入れた覚えはないけどなぁ…

とりあえず検索すると

TWAIN プラグインの読み込み中にアプリケーションが終了する(Photoshop Elements 4.0/5.0/Photoshop CS2/CS3)

これらしい。

原因となるドライバが不明なので、TWAINプラグイン自体外すことにした。説明の通りにプラグインのファイル名の先頭に「~(チルダ)」をつけるだけでOK。

会社で使ってるPCだからTWAIN経由ではスキャンしないしね。

で、思ったのは、AdobeのTechNoteに大抵の問題は情報があるらしいということ。

Photoshop他Adobe製品で起動しないとかの対応方法を探すには、ちゃんと正確にどこで止まったかを調べないといけないってことですな。基本だけど。「Photoshop 強制終了」とかで探すとハマるよ!