supplibceを使う

supplibceライブラリは、Windows CE 5.0 Standard SDK CRT supplementary libraryと言うことで、New BSD License(3-clause BSD License)で公開されています。

Microsoft (eMbedded) Visual C++でWindows CEアプリケーションの開発をするとすぐに思い知らされることがあります。9x系やNT系のWindowsのWin32 APIやCRT関数の多くは使用できるのですが、いくつかは実装されていなかったり、処理内容が異なったり、別のAPIになっていたり、CRTでは宣言だ けされているものさえあります。
supplibceは、そんなCRTの憂鬱な状況をちょっとだけ緩和させるために用意した簡易実装ライブラリです。

まぁ、別にわざわざsupplibceライブラリを使用しなくてもWin APIで書けば良いだけと言えば、そうなのですが、WinCE、Windows、Unix系に可能な限り同一のコードで対応したいという欲求があり、使ってみました。

以下の注意事項があるので、もちろん自己責任で。

supplibce comes with ABSOLUTELY NO WARRANTY.
あくまで互換性確保のための簡易実装です。エラー時のerrno値の設定や、スレッドセーフなどはほとんど考慮していません。ミッションクリティカルな用途には(そのまま)使用すべきではありません。使用する場合は適宜修正すべきです。

ビルド方法は、以下のような感じです。なお、eVC環境を使ったビルド方法です。

  • ダウンロードしたファイルを展開するとarm.makとincludeおよびsrcフォルダが飛び出てきます
  • コマンドプロンプトを立ち上げます
  • 展開したフォルダにCDします
  • 環境設定用のバッチファイルを編集します

デフォルトでeVCをインストールしている場合は以下のフォルダに存在するはずです

"\Program Files\Microsoft eMbedded C++ 4.0\EVC\wce500\bin\"

で、ARM用にビルドするのであれば、WCEARMV4I.BATをベースに自分の環境に合わせてバッチファイルを編集します

編集するのは、PLATFORM、WCEROOT、SDKROOT変数に設定している値くらいと思います

どのような値にするべきかは、eVCを立ち上げていつもビルドしている状態で「ツール」→「オプション」→「ディレクトリ」タブを見れば設定するべき値がわかると思います

  • NMAKEする

nmake arm.mak

以上でlibフォルダが作成され、その中にsupplibce.libが生成される

後は、このライブラリを使いたいプロジェクトでリンクすればOKです。

あ、展開されたインクルードファイルも適切なフォルダにおいてプロジェクトのインクルードパスを通さないとコンパイルが通らないですね :)

TrackBack URL :

シリアル通信(WinCE⇔wincom.rb)でハマる

WindowsCE機のシリアル通信プログラムを試験するためにWindows側の対向プログラムをRuby+wincom.rbで書いてみました。

CやC++で書くのも仰々しいし、C#って線もあったけど…試験用の対向プログラムなので、スクリプト言語で安易にちょこちょこ修正できた方が便利ってことで、Ruby+wincom.rbを選択したわけです ;)

まぁ、シリアルを制御するためのスクリプト言語にはRuby以外の選択肢もあったし、Rubyにしてもwincom.rb以外にも数種類の選択肢があったわけですが…対向用のマシンはWindowsだったし、使い方もすごく簡単そうだったのでwincom.rbを採用しました。

機器間は直結のシリアルケーブルで接続していたのですが、WindowsCE機側のPCとの通信設定で「PCとのケーブル接続を有効にする」状態にして、wincom.rbでシリアルポートをオープンするとActiveSyncを試みるという不可解な現象が :roll:

wincom.rbを調べてた時に以下のようなページを見つけていたので、最初はてっきりノイズでも :?: と思ったわけですが…。

原因はまったく違って、wincom.rbのポートオープン処理にあった以下のコードが原因でした。今回のケースでは、該当部分をコメントアウトすることで事なきを得たわけですが :)

    bi = @@wEscapeCommFunction.call(@iht,setdtr)    #DTR ON

DTRをオンしているだけなので、普通ならまったく問題ないと思うのですが…DTR信号に反応して、ActiveSyncしようとする挙動の理由が良くわからないんですが… :| そういうモノなんですかね :?:

Rubyスクリプティングテクニック ―テスト駆動による日常業務処理術 Rubyスクリプティングテクニック ―テスト駆動による日常業務処理術
菅野 良二

Rubyによるデザイン・パターン Rubyレシピブック 第2版 268の技 プログラミング言語 Ruby Ajax on Rails Railsレシピブック 183の技
by G-Tools

TrackBack URL :

WindowsCEでコンパネを一時無効に

よく忘れるので、自分用メモ :)

WindowsCE5のタスクバーに表示されてる「時計をタップしても時刻変更はできないようにしたい」と言われる。でも、時計を消すのはなしね。

要するにアプリケーションが動作している期間だけ、時刻変更はされたくないと。確かに理由はわからないでもない。Windowsメニューやタスク切替メニューは強引に止めているので、確かに片手落ちっぽい。

時刻変更くらいと甘くみてました :cry:

どうやって時刻変更を抑止しようかと考えたのですが、コンパネを抑止してしまえばよいじゃないと :idea: 抑止自体は前にも実施したことがあって、何もしないアプリケーションを作ってCopyFileで以下のファイルを上書きしてしまえば抑止できます ;)

\Windows\ctlpnl.exe

コンパネがまったく開かなくなりました。では、アプリケーション終了時に元に戻すには :?: DeleteFileで上書きした上のファイルを消してしまえばオリジナルのコンパネが復活してきます。今回の要件にはバッチリですね ;)

Windows Embedded CE 6.0組み込みOS構築技法入門 (マイクロソフト公式解説書) Windows Embedded CE 6.0組み込みOS構築技法入門 (マイクロソフト公式解説書)
松岡 正人

はじめてのWindows Embedded CE6―OSの設計からアプリケーション開発まで (I・O BOOKS) Windows Mobileプログラミング徹底理解 はじめてのWindowsCE―OSの設計からアプケーション開発まで (I・O BOOKS) Programming Windows Embedded CE 6.0 Developer Reference (PRO-Developer) Windows Mobile 5.0 アプリケーション開発 Beginner's Book (Gihyo Technology)
by G-Tools

TrackBack URL :

DjVu形式ってなかなか良いかも

WindowsCE上でのPDF形式サポートがイマイチなので、DjVu形式について調べてみました。

まず、DjVu形式を作るためのソフト…たぶん、選択肢はあまり多くない :?: Windows向けには以下の3つしか見つけられてないです(Linux向けにはもう少しありそうですが)~さらに試したのは2つだけ。他にあったら教えてください。

Celartemからリリースされている商用ソフトで30日間と500ページという制約付きの評価版を試してみました。

プリンタとして動作するタイプで何の問題もなく綺麗に変換できます。さすが商用…でも、結構高い『Document Express with DjVu 価格表』です。

pdf2djvuと言うことで、PDF形式からDjVu形式へ変換してくれるコマンドのWindows版を試してみました。

なかなか良い感じで綺麗に変換してくれます。これを採用しようと思ってます ;)

あと、シナリオ・データと画像データを読んで、DjVu形式の文書を作成するための処理を行うPerlプログラムMyDjVuもあるらしいのですが…色々なソフトが必要なので試してません :arrow:

あと、Acrobat 9.1で標準の変換では文字が欠ける現象が発生するWord文書があったのですが…どうも、XP SP3のPscript5.dllが原因のようですね~以下の対処で直りました ;)

問題の有無に関わらずWindowsXP-KB950305-v2-x86-JPN.exeを実行です :)

で、肝心のDjVu形式のビューワですが…WindowsCE用には以下があります。

なかなか良い感じです ;) GPLでソースも公開されているので、少し弄ってみています。

気になるのはDjVuのWindows向けの標準ビューワと思われるLizardTechのものに米国特許6.058.214および出願中の特許で保護されてるとか書かれてること。

この辺りが理由で、『ライセンス両立性の罠 – SourceForge.JP Magazine』のようなことが起こっているっぽいですね。

とにかく、DjVuDjVu 形式は良い感じなのでもっと普及して欲しいものです。

TrackBack URL :

PDFが全然ポータブルじゃない?

Portable Document Formatを略したのが、PDFPDF なのでポータブルつまり特定の環境に依存しないドキュメントフォーマットのはずなのにWindowsCE系では困ったことに良いPDFビューワがない感じ :?:

本家のAdobeがリリースしてくれれば良いんだけど…Adobe Reader for Pocket PCで公開されているものはPocketPCやWindows Mobile向けで、今回の機種はインストーラで弾きとばされてしまう。CAB形式で単体配布してくれないかなぁ~動くか微妙だけど :roll:

ちなみにAdobe Reader LEも入手してみたのですが…インストールできませんでした(WinCE CAB Managerも試したけど無理っぽいです)。

で、ClearVue PDFというPDFビューワがプリインストールされてるんだけど…このビューワが曲者。きちんと表示できるPDFの形式に相当制約があります :|

元々、表示したいファイルはWord形式でAdobe Acrobat 9.1で何も考えずに変換したPDFでは読み込むことすらできない :shock: パラメータを調整すると文字と図は表示できたものの表の線が表示されない :roll:

仕方ないので色々試してみると、クセロPDF2が一番相性が良いことが判明。でも、相性が良いだけで問題はあって、図を表示できるようにするとPDFのサイズが無茶苦茶大きくなってしまう。

で、WindowsCEで動くPDFビューワを探すと優秀なものがあるにはあるんですが…。

商品だけあって、ユーザインタフェースもPDFのレンダリングエンジンも優秀。でも、台数が半端ないので無料じゃないとつらい。

Xpdfが優秀なので以下のソフトには期待したのですが…日本語がダメっぽいです。まぁ、No support for non-western character encodingsって明記されてますけど…何か方法があれば教えてください ;)

そう言えば、Microsoft製のPDFビューワもあるんですよね~残念ながら今回の機種には入ってません。ぜひ試してみたいところです。

どこかに無料で優秀なWindowsCEで動作するPDFビューワはないのかなぁ :? と悩んでます。どなたかご存知ないですかぁ~教えていただけるとウレシイです。

仕方ないので、PDF形式をあきらめてDjVuDjVu 形式を採用してみようかと検討中。

TrackBack URL :

SIP(SoftwareInputPanel)をドラッグできないように

結構、探すのに手間取ったので自分メモ ;)

SIP

WindowsCEでSIP(SoftwareInputPanel)を移動できないようにしたかっただけなんです。でも、検索してもうまく見つけられず何か良い方策はないものかと思案していたわけですが…あっさりとレジストリの設定でできたんですね :roll:

探し回って見つけたのは以下のページ。

CodeProjectは最初の方で検索したんだけど…タイトルに騙されてました :|

結論としては、以下のレジストリ値を変更してリセットするだけです。

HKEY_CURRENT_USER\ControlPanel\Sip\DragStyle

DragStyleを0にすると思惑通り、SIPがドラッグできなくなりました ;)

でも、もう一つ課題があってSIPのメニューから「入力パネルを隠す」って項目だけ効かないようにしたいんですよね。何か良い方法があるなら、教えていただければウレシイです。

Windows Embedded CE 6.0組み込みOS構築技法入門 (マイクロソフト公式解説書) (マイクロソフト公式解説書) Windows Embedded CE 6.0組み込みOS構築技法入門 (マイクロソフト公式解説書) (マイクロソフト公式解説書)
松岡 正人

はじめてのWindows Embedded CE6―OSの設計からアプリケーション開発まで (I・O BOOKS) Windows Mobileプログラミング徹底理解 Programming Windows Embedded CE 6.0 Developer Reference (PRO-Developer) はじめてのWindowsCE―OSの設計からアプケーション開発まで (I・O BOOKS) Windows Mobile 5.0 アプリケーション開発 Beginner's Book (Gihyo Technology)
by G-Tools

TrackBack URL :

CでGetPrivateProfile*を使わずにINIファイルを扱う

以前、『Slashcolon /: » C#でGetPrivateProfile*を使わずにINIファイルを扱う』というエントリで超適当なコードを晒したわけですが…今回は、そのC言語版です ;)

要するに客先指定で、C#ではなくC/C++で書くのが命題なので仕方ない。フラットホームは前回同様WindowsCEなので、GetPrivateProfileStringとかのWinAPIはありません。WindowsCEでもMFCを使うのであれば、AfxGetApp()->GetProfileString(…)とか使えるんですけど…今回はMFCもなし。

最初、CodeProject辺りで誰か作ってくれてないか検索してみたのですが…見たものは全て内部でGetPrivateProfileStringを使ってました。要するにWinAPIをラップしてC++のクラスとして公開してるものがほとんど :|

残念ながら、WindowsCEじゃ使えないので前回同様に超適当にでっち上げてみた。

今回のは、空白とかも無視しないしINIファイル形式をガチガチに規定してるので使用は運用でカバーできる場合のみ、さらに問題があっても前回のC#版同様自己責任ってことで。もちろん、コメント、バグ報告、改善要望etc.は歓迎します ;)

#define BUFSIZ 512
 
TCHAR *GetString(TCHAR *Section, TCHAR *Key, TCHAR *Default, TCHAR *IniFile)
{
    TCHAR    buffer[BUFSIZ];
    TCHAR    token1[BUFSIZ], token2[BUFSIZ];
    TCHAR    section[BUFSIZ];
    TCHAR    *p;
    BOOL      sectionFound = FALSE;
    FILE        *fp;
 
    if ((fp = _tfopen(IniFile, _T("r"))) == NULL) {
        return(_tcsdup(Default));
    }
 
    _sntprintf(section, sizeof(section), _T("[%s]"), Section);
 
    while (_fgetts(buffer, BUFSIZ, fp) != NULL) {
        if ((p = _tcschr(buffer, L'=')) != NULL) {
            *p = L' ';
        }
        _tcscpy(token1, _T(""));
        _tcscpy(token2, _T(""));
        _stscanf(buffer, _T("%s %s"), token1, token2);
        if (_tcscmp(token1, section) == 0) {
            sectionFound = TRUE;    // 指定セクション発見
        } else {
            if (*token1 == L'[') {
                sectionFound = FALSE;    // 別セクション発見
            }
        }
        if (sectionFound == TRUE) {
            if (_tcscmp(token1, Key) == 0) {
                // 指定セクションの指定キーを発見
                fclose(fp);
                return(_tcsdup(token2));
            }
        }
    }
    fclose(fp);
    return(_tcsdup(Default));
}
 
int GetInt(TCHAR *Section, TCHAR *Key, int Default, TCHAR *IniFile)
{
    TCHAR    *p;
    TCHAR    *endp;
    long    l;
 
    p = GetString(Section, Key, _T(""), IniFile);    // 文字列として取得
    if (p != NULL && _tcscmp(p, _T("")) != 0) {
        // 指定のセクションとキーが見つかった
        l = _tcstol(p, &endp, 0);
        if (*endp == L'\0') {
            free(p);
            return((int)l);    // long値をintへ
        }
    }
    free(p);
    return(Default);
}

GetString関数の戻り値領域は_tcsdupで確保されるので、厳密に言えばfreeで解放が必要です。でも、たいていの場合は初期時に読み込んで終了まで保持しておくことが多いと思うので神経質になるほどでもないかと思いますが…。

━超適当な作りだなぁ~ :oops:

もっと、効率的でスマートな方法があると思うので教えていただければうれしいです。

TrackBack URL :

VS200XとIE8βのJScriptの相性が悪い件

VS200X(VS2005, VS2008)でスマートデバイス向けにMFCアプリケーションを新規作成しようとすると…ウィザードが表示されるまでは良いのだけど、プラットホームを選択するウィザード画面を表示しようとすると墜ちる :|

正確な現象としてはウィザードが墜ちて、新規プロジェクトの作成画面へ戻ってしまう。

なので、前に経験した『Slashcolon /: » VS2005でスマートデバイス用MFCアプリが作れない?』に似てるけど違う現象 :arrow:

多くのデバイスのSDKを疑ったり、複数の開発環境(eVC, VS6, VS2003, VS2005, VS2008)が入っていることを疑ったり、色々遠回りをしたわけですが…同じ現象に陥っている方を発見 :idea:

まさに同じ現象 :!: IE8βをIE7に戻して回避されたようですが…わたしは、とりあえず原因はハッキリしたのでウィザードは別環境で動かすことにしてIE8のまま様子を見ることにしました ;)

JScript.dllをIDEのフォルダにコピーしたりDLLの検索順で回避できないか探ってみましたが難しいみたいですね~何か良い方法があれば教えてくれるとうれしいです。

しかし、調べる過程でウィザードの中身をチラ見してたんですけど…なぜ、わざわざウィザード部分をHTML+JScriptなんて構成で作ってるんですかね。それほどメリットがあるとは思えないんですけど :|

追記 2009-01-27 10:00:09
IE8 RC1がリリースされJScript.dllのバージョンが上がり以下の強引な修正を行わなくても良くなったようです。
直ったのはうれしいのですが、直し方を見つけた途端にRC1リリースで直るなんて :shock:

追記 2009-01-24 23:12:09
ほぉ~HTML+JScriptな構成になっているのは「ウィザードのカスタマイズ」にあるようにカスタムウィザードを作れるようになんですね。だとしても良い選択とは思えないんですけどね。

あ、それは置いといて…ものすごく強引なんですけど以下のファイル(VS2008の場合)を編集してIE8βのままでもウィザードが動くようになりました。

  C:\Program Files\Microsoft Visual Studio 9.0\VC\VCWizards\SmartDeviceAppWiz\
  mfc\Application\html\1041\Platforms.htm

に書かれている以下の例外処理を2箇所ほどコメントアウトして握りつぶしました。

  window.external.Finish(document, 'cancel');

さらにInitDocumentの中の以下の4行もコメントアウトして、初期表示時に1個のプラットホームをデフォルト選択する処理を停止しました。

  AvailableSDKs.options.remove(0);
  SelectedSDKs.options.add(node);
  SelectedSDKs.selectedIndex = 0
  AvailableSDKs.selectedIndex = -1;

それほど悪い動作はしないと思いますが…あくまで自己責任でお願いします ;)

追記 2009-03-30 09:29:08
どうも、IE8正式版にして同様の問題が再発しているようですが…上記の対策では直らないです。と言うか現象が微妙に異なりますし。ほんとMS何してるの :|

TrackBack URL :

"愛々,1".IndexOf(",")は1?

結構ヒドイバグですね :roll:

ちなみに.NET Compact Framework 2.0では大丈夫でした。

ちゃんとマイクロソフトには、報告を入れてくれてますが…。

いつ直るかなぁ :arrow: もしや、コレもIMEとかのようにチャイナクオリティですか :?: それとも、日本語が亡びる前兆ですか :mrgreen:

TrackBack URL :

複数選択可能なListViewコントロール

いや、もちろんCompact Frameworkでなければ…ListViewのMultiSelectプロパティをTrueにするだけ ;)

なので、ListViewコントロールを見ると…ないよ :shock: でたぁ~また、Compact Frameworkにはない :arrow:

要するにチェックボックス付きがあるだろう…ってのがMS様の言い分なのかな :?: 仕方ないので、Google先生に訊いてみるが…なかなか答えてくれない :cry:

そんな中、CodeProjectで見つけたのはCompact Frameworkとは全く関係ない…以下のXPTableというListView拡張で、何かの機会に使うためにメモ :)

あ、Compact Frameworkでした。調べてると同じことで質問してる人は居るんだけど…なかなか望んだ回答がでていないなぁ~と思っていると以下のページを発見。

ページの中にuuencodeされたMultiSelectListView.zipというファイルが貼り付けられてるなぁ~内容はわからないけど、どにかくエディタに貼り付けて…改行コードをLFで保存して、Cygwinのuudecodeでファイルを取り出してみた。なんか、uudecodeなんて使うの超ひさしぶりだなぁ~なんて思いつつ。

でてきた、MultiSelectListView.zipを展開すると…おぉ、VB.netのコードだったのね。量からみて、大きくないのはわかっていたので中身を見てみる。

なるほどポイントは、P/Invokeを使ってSetWindowLongを呼び出して、ウィンドウ(ListView)のLVS_SINGLESEL属性を外してやることだけなのね :idea: わかってみれば、なるほどなんだけど…思いつかなかったなぁ。

と言うことで、C#に書き直したポイントだけのコードをペタっとしておきます ;) ありゃ、わざわざGetCaptureしてウィンドウハンドルを取らなくてもListViewのプロパティから取れますね :arrow:

    private const int GWL_STYLE = -16;
    private const int LVS_SINGLESEL = 0x4;
 
    [DllImport("coredll.dll")]
    static extern IntPtr GetCapture();
    [DllImport("coredll.dll", SetLastError = true)]
    private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
    [DllImport("coredll.dll", SetLastError = true)]
    private static extern UInt32 GetWindowLong(IntPtr hWnd, int nIndex);
 
    private void EnableMultiSelect(ListView listView)
    {
        listView.Capture = true;
        IntPtr hWnd = GetCapture();
        listView.Capture = false;
        uint style = GetWindowLong(hWnd, GWL_STYLE);
        SetWindowLong(hWnd, GWL_STYLE, (int)(style & ~LVS_SINGLESEL));
    }

このEnableMultiSelectメソッドをListViewを使うフォームのコンストラクタあたりで、複数選択させたいListViewを引数にして呼べば幸せになれるかも知れません。

さらに、CtrlキーやShiftキーを同時押下するのが面倒(ソフトウェアキーボードだもんね)なんて場合は、ListViewのフォーカスイン時とフォーカスアウト時にCtrlキーを制御してフォーカスのある間はCtrlキーを押した状態にしておけば…さらに幸せになれるかも知れません ;)

Ctrlキーを制御するコードもついでなのでペタっと。

    private const byte VK_CONTROL = 0x11;
    private const int KEYEVENTF_KEYDOWN = 0x0;
    private const int KEYEVENTF_KEYUP = 0x2;
 
    [DllImport("coredll.dll", EntryPoint = "keybd_event", SetLastError = true)]
    internal static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo);
 
    private void FocusIn()
    {
        keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYDOWN, 0);
    }
 
    private void FocusOut()
    {
        keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
    }

あ、あと選択されている項目を取り出すコードもペタっとしとかなきゃ。

    ListView.SelectedIndexCollection collection = listViewMulti.SelectedIndices;
    int count = collection.Count; // 選択されている個数がcountに
    foreach (int i in collection)
    {
        // iに選択されているリストのインデックスが順次入る(当然0からの値)
    }

追記 2008-11-10 21:24:25
Ctrlキーの同時押しですが…FocusInとFocusOut時の制御では、やはり制御しきれないみたいです :|
結局、ListViewのWinProcをフックしてWM_LBUTTONDOWN時にMK_CONTROLビットをORすることで同時に押されている状態としました。
さらに、WM_LBUTTONDBLCLKとWM_KILLFOCUSメッセージを無視するようにすると…さらに幸せになれるかも知れません。

さらに追記 2008-11-13 01:13:25
WinProcのフックですが…『WndProcHooker クラスを使用する』のやり方を忠実に実装しました。当初、安易な方法で実装したら…最小化、最大化などを行うと思わぬ挙動をして半泣き。
なので、結局カスタムコントロール化してEnableMultiSelectと同様の処理をコンストラクタで行うようにして、ようやく最終形ができあがりました。
確かにカスタムコントロール内で全て閉じたのでコードは綺麗になったけど…超面倒ですね :|

TrackBack URL :