StyleCop 4.4.0.9日本語化版登場!

『Microsoft StyleCop 4.3(C#静的解析ツール)リリース』のエントリにコメントでStyleCopを日本語化したというお知らせをいただきました。小沢さん、ありがとうございます :)

連絡をいただいた時にja1-1版を試してみたのですが…どうもうまくインストールされず直接コンタクトしてみるかなぁ :?: と思っていたところにja1.2版がリリースされたので試してみたらうまく日本語化されました ;)

少し前にStyleCopのソースが公開されていたので、警告メッセージのXMLファイルだけのなんちゃって日本語化をしようと思いながら手つかずだったわたしとしては、非常にウレシイ公開です。

ちなみに、わたしが試した環境はWindows 7 + VS2010 Professional日本語版です。あと、VS2008 Proでも問題なく動作しているようです。

StyleCop日本語化

StyleCop日本語化出力

StyleCop日本語化警告メッセージ

StyleCop日本語化警告メッセージ

やはり、日本語で表示されるのは良いですね ;)

TrackBack URL :

Doxygenコメント書き補助用VSアドイン

C#でコメントを書くなら、XML + Sandcastleで決まり。では、C++ならDoxygenでしょう ;)

と言うことで、一度作りたいと思っていたVSアドインとしてDoxygenコメントの入力補助が作れないかなぁ~と調べてみたら…やはり、みなさん同じことを考えるわけですでにありました。

とりあえず2つ見つかったんで、忘れないように自分用メモ。他にもっとあったりして :)

で、どちらを使おうかで悩み。さらに、どちらもカスタマイズはできるものの…自分の思い通りにはならないし。

ならば、やっぱりお勉強も兼ねて自作するかを思案中 :?

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 :

ULONG(const ULONG &)の罠

一緒に仕事している人がハマってた。昨日まで動いていたコードが少し変更したら動かなくなったと…まぁ、この世界じゃよくある話ですよね ;)

言語はVC++、墜ちるところは一見DBアクセスの関数内。まぁ、CやC++はメモリ管理は自己責任なんで実際に墜ちる場所と原因の場所が異なることが多く原因が見つけにくい時が良くあります。まぁ、今回もそんなケースですかね。

以下のコードは、実際とは異なるわけですが…やりたいことはULONG型の領域をn個確保したいと言うことです。

ULONG *a = new ULONG(n);

1行だけであれば、すぐに変だとわかりますよね~まぁ、考えてみればあたり前なんですが…コンパイルエラーにはなりません :| 単にULONGで初期値が10の領域が1個だけ確保されて、そのアドレスがaに代入されます。

ULONG *a = new ULONG[n];

これなら、n個のULONGの領域が確保されます。()と[]で大違いですね~まぁ、実際のコードはもう少し入り組んでるので、この間違いを探すのに結構な時間を要してしまいました…二人がかりで :oops:

しかし、ULONGって以下のように定義されてるだけのはずなのにVSでインテリセンスが働くのが不思議なんですよね :roll: 理由がわかる人は教えてください。

typedef unsigned long ULONG;

以下のような感じで…でも、newを前に置くと効かないんですけどね。

ULONG

で、わたしが今まで同様の罠に引っかからなかった理由を考えてみました。

ULONG *a = (ULONG *)malloc(n * sizeof(ULONG));

まったく、C++風じゃないんですけど…mallocで確保してましたとさ。わたしの場合newはインスタンスを作るものってイメージが強いので、基本型の領域を確保したい場合はmallocの方が好きなんですけどどうなんでしょうね。

VC++だとnewでメモリ領域が足りなかった場合try…catchしてないとデフォルトのメッセージボックスが表示されちゃうんですよね(Releaseモードの場合)~かと言って、newに例外書くのも気持ち悪いし…まぁ、mallocでもNULLチェックしなくちゃいけないので同じと言えば同じなんですけど。

ひと目でわかるMicrosoft Visual C++ 2008 アプリケーション開発入門 (マイクロソフト公式解説書) ひと目でわかるMicrosoft Visual C++ 2008 アプリケーション開発入門 (マイクロソフト公式解説書)
増田 智明

プログラムを作ろう! Microsoft Visual C++ 2008 Express Edition 入門 (マイクロソフト公式解説書) これからはじめるVisual C++2008―Visual C++2008 Express Edition対応 ひと目でわかるMicrosoft Visual Basic 2008 アプリケーション開発入門 (マイクロソフト公式解説書) ひと目でわかるMicrosoft Visual C# 2008 アプリケーション開発入門 (マイクロソフト公式解説書) Visual Studio 2008 Standard Edition
by G-Tools

あ、typedefにミソがあるのかぁコレ :idea:

TrackBack URL :

ErrorProviderの自分メモ

.NET Frameworkの流儀に従うならば、バリデーションチェックはErrorProviderクラス(System.Windows.Forms)を使うのが粋ってものらしい。

ならば一度使ってみるかと思い初体験してみた :) え、今まで何で使ってないんだって…C#でバリデーションの必要なUI作るの初めてだし、Compact Frameworkにはないしね~と言い訳 ;)

デモプログラムなんで、入力は一箇所だし非常に簡単なので以下のあたりを参考に適当に実装してみた。

ほぉ、簡単にできるなぁ~入力異常時に表示されるデフォルトのアイコンがちょっとウザイけど…まぁ、こんなもんだろうと。

ところが…エラーがある状態だとウィンドウクローズでプログラムの終了ができない罠 :shock:

フォームのAutoValidateプロパティがデフォルトでEnablePreventFocusChangeになっているためのようです。かと言って、他のに変えるのも面倒だし…と言うことで検索。

おぉ、すごいちゃんとカスタムコントロール化してる人が居るじゃないですかぁ。

ちょっとソースを拝見…ここまでのものは今は要らないけどテストプログラムも付いてるので動きを見るのに最高です :!:

で、少し追ってみると :idea: なるほど、エラーがある状態でもプログラム終了できるようにしたければ…フォームのCloseingイベントでe.Cancelをfalseにしちゃえば良いみたいですね ;)

C#クックブック 第3版 C#クックブック 第3版
鈴木 幸敏

絶対現場主義Visual C#実践講座―開発の現場から生まれた実践テクニック&TIPS集 LINQテクノロジ入門~Microsoft Visual Studio 2008による新たなクエリ構築技法~ (マイクロソフトコンサルティングサービステクニカルリファレンスシリーズ) (マイクロソフトコンサルティングサービステクニカルリファレンスシリーズ) Microsoft Silverlight 2テクノロジ入門 (マイクロソフト公式解説書) C#エッセンシャルズ 第2版 プログラミングMicrosoft ASP.NET 3.5 (マイクロソフト公式解説書 Microsoft Visual Studi)
by G-Tools

TrackBack URL :

ハンドルされていない例外の捕捉でハマル

C#でシリアル通信のプログラムを書いてたわけですが…最近はCOMポートを持っていないマシンが多く、わたしの使ってるマシンも標準ではCOMポートがありません。

そこで、以下のUSB-シリアル変換器を使ってるわけです。COM番号etc.の設定もできるしなかなかの優れもの。

B000ANR7T4 REX-USB60F USB-Serial Converter
ラトックシステム 2005-06-30

by G-Tools

アプリケーションから見ると普通のCOMポートとなんら変わりなく扱えます。

そこで、ちょっとした出来心が…実行途中でUSB-シリアル変換機を抜いてからアプリケーションを終了すると。COMポートを閉じに行くところで…うぎゃ~system.dllでハンドルしてない例外が飛び出てアプリケーションエラー発生 :| ポートをクローズするところのtry…catchでは捕まえられないんですね :shock:

まぁ、以下にあるMSDNのサンプルでも同じ現象なのでヨシですね(違。

まぁ、実段階ではCOMポートを装備したマシンを使うので、ポートがなくなるなんて事態はありえないわけですが :arrow:

でも、アプリケーションエラーがでるのはキモチ悪いので『@IT:.NET TIPS 適切に処理されなかった例外をキャッチするには?』あたりを参考に捕捉してみました。

確かに捕捉はできたのですが、MessageBoxをわざわざ表示することもないかと思いUnhandledExceptionを握りつぶすだけにすると…。

ぎゃあ~アプリケーションエラー復活

仕方ないので、さらに検索してみると…

のようにUnhandledExceptionハンドラでEnvironment.Exitを呼び出してる人が結構いるようなので真似してみたら…アプリケーションエラーはでなくなりました ;)

どうも、UnhandledExceptionが発生した時の状態にはMessageBoxで止まったり、止まらなかったり数種の状態がある感じがします。

なので、UnhandledExceptionのハンドラではMessageBoxとかは使わずにコンソールやログ出力だけして、Environment.Exitを呼び出して終わるのが「吉」っぽいと言うのが結論でした。

ちゃんちゃん :roll:

TrackBack URL :

ALT+Tabチックなプログラムを書く…オナードローCListBox編

以下のエントリの一応続編です ;) とりあえず、このエントリでALT+Tabチックなプログラムのメモは終了です。

切替タスクの名前とアイコンが取得できたので、表示する必要があります。とりあえず、リストボックス(CListBox)で表示することにしましたが…標準のCListBoxでは、アイコンを併せて表示することができません :|

そこで、CodeProjectを検索してでてきたのが「Graphic and text ownerdraw listbox」です。サンプル画面を見る限り、今回の用途には十分そうです。使うのも簡単ですね。

リストボックス部品を貼って、COwnerDrawListBoxクラスとしてメンバー変数(例えばm_OwnerListBox)を作ってアイテムを設定したいところで以下のような感じで書くだけです :)

m_OwnerListBox.Add("アイテム1",
               ::AfxGetApp()->LoadIcon(ICON_ITEM1));
m_OwnerListBox.Add("アイテム2",
               ::AfxGetApp()->LoadIcon(ICON_ITEM2));

あとは、アイコンとテキストの位置関係の設定を以下のような感じで。

m_OwnerListBox.SetTextPosition(COwnerDrawListBox::ITEM_LEFT);
m_OwnerListBox.SetIconPosition(COwnerDrawListBox::ITEM_RIGHT);

上記の場合だとテキストが左側にアイコンが右側に表示されます。

そして、リストボックスが不要になった時点で以下のコードでメモリを解放すればOKです。

m_OwnerDrawListBox.Destroy();

ところが、COwnerDrawListBoxには2つほど問題がありました :|

  1. SetTextPositionとSetIconPositionで両方を同じ側にした場合の動作
  2. VS2005で動作させると実行時エラーを起こす

1の方は仕様かも知れませんが…アイコンを左側、テキストを右側にしたかったので設定するとテキストが右寄せになってしまいます。わたしは、右寄せは嫌だったので両方左側に指定してみました。すると、テキストとアイコンが左側で重なってしまいました :roll: たぶん、これも仕様なのでしょう。

でも、それ以上の細かな位置制御はなかったので結局…COwnerDrawListBox::DrawItemメソッド中の右寄せをしている以下の部分を変更しました。

// pDC->DrawText(pListDataItem->strItemData,
//             strlen(pListDataItem->strItemData),
//             rectText,
//             DT_RIGHT | DT_SINGLELINE | DT_VCENTER);
 
pDC->DrawText(pListDataItem->strItemData,
            _tcslen(pListDataItem->strItemData),
            rectText,
            DT_SINGLELINE | DT_VCENTER);

ITEM_LEFT, ITEM_RIGHTで面倒な条件を組んでありますね :roll: 自分のやりたい位置制御がハッキリしているなら、思い切り書き直した方がよいかも知れません :arrow:

次に2の方ですが…VS6でデバッグしている時は問題なかった(表面化しなかっただけですが)のですが、透明化の際にVS2005でデバッグ実行するとエラーになり見つかった問題です。同じくCOwnerDrawListBox::DrawItemメソッド中でのCDCクラスの扱いが良くないようです。

CListBox::DrawItem (MFC)の例に合わせて以下のように変更しました。

//  CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
 
    CDC dc;
    dc.Attach(lpDrawItemStruct->hDC);
    CDC *pDC = &dc;
 
...
 
//  pDC->Detach();
    dc.Detach();

何だか最終的にはCOwnerDrawListBox::DrawItemメソッドを書き直しちゃったので、使う意味はなかったかも知れません。DrawItemメソッドがほとんど全てですし :mrgreen:

できあがったタスク切替のイメージは以下のような感じです ;)

ALTTAB

TrackBack URL :

ALT+Tabチックなプログラムを書く…なぜかウィンドウ透明化編

『Slashcolon /: » ALT+Tabチックなプログラムを書く…切替タスク取得編』『Slashcolon /: » ALT+Tabチックなプログラムを書く…アイコン取得編』の一応続編です ;)

アイコンに引き続いて、どうでも良い見た目の実装なんですけど…表示するウィンドウというかダイアログの透明化です。実装したことがなかったので、なんとなくやってみたかっただけなんですけど。

透明化って、むちゃくちゃ簡単でWS_EX_LAYERED属性をウィンドウに付けて、SetLayeredWindowAttributesで透明度を設定すればハイ終わりって感じなんですね。

ところが…
VS6だけだとWS_EX_LAYEREDが定義されてないとか、SetLayeredWindowAttributesがリンクエラーになったりするんですね :shock:

要するにウィンドウの透明化って、Windows 2000からのものなんでPlatform SDKを入れてWINVERを…みたいなことをする必要がある。でも、VS6での開発は客先指定なのでSDKを入れるのはチョットってことでuser32.dllをダイナミックに呼び出すことに。

まぁ、DLLをダイナミックに呼び出す方法は珍しくもなんともないんだけど…ペタっと貼っておく。

    // 本来はSDKで定義されてる値
#define LWA_ALPHA 0x00000002
#define WS_EX_LAYERED 0x00080000
    // 透明化レベル 0~255 0で透明
#define ALPHA_LEVEL 200
 
   // 関数ポインタの型定義
typedef BOOL (WINAPI *LPFNSETLAYEREDWINDOWATTRIBUTES)(HWND, COLORREF, BYTE, DWORD);
 
    // 以下のコードをOnInitDialog辺りに
    LPFNSETLAYEREDWINDOWATTRIBUTES SetLayeredWindowAttributes;
 
    LONG exStyle = ::GetWindowLong(this->m_hWnd, GWL_EXSTYLE);
    ::SetWindowLong(this->m_hWnd, GWL_EXSTYLE, exStyle | WS_EX_LAYERED);
 
    HMODULE hModule = ::LoadLibrary("user32.dll");
 
    SetLayeredWindowAttributes =
        (LPFNSETLAYEREDWINDOWATTRIBUTES)::GetProcAddress(hModule,
            "SetLayeredWindowAttributes");
 
    SetLayeredWindowAttributes(this->m_hWnd, NULL, ALPHA_LEVEL, LWA_ALPHA);
    ::FreeLibrary(hModule);

これで、VS6標準で問題なくコンパイルできました ;) あ、モチロンVS2005とかVS2008なら、わざわざこんなことしなくても普通にコンパイルできるんですけど。

そう言えば、Channel 9では「Visual C++ 10: 10 is the new 6」というテーマでC++チームのプログラムマネージャーAmit Mohindra氏が語ってます。

30分以上の長丁場ですが…VC++ 10(VS2010)では、簡単にOffice 2007とかで採用されてるリボンインタフェース(評判の良いやつです :mrgreen: )が実装できることや、超簡単に自動保存機能が実装できること、さらにはC++0xの一部を取り入れてることなどを語っています。

C#に主役の座を譲りつつあるように見えるけど…まだまだMSはC++もがんばってるよぉ~って感じですね ;)

Programming: Principles and Practice Using C++ Programming: Principles and Practice Using C++
Bjarne Stroustrup


Amazonで詳しく見る
by G-Tools

TrackBack URL :

ALT+Tabチックなプログラムを書く…アイコン取得編

『Slashcolon /: » ALT+Tabチックなプログラムを書く…切替タスク取得編』の一応続編です。

まぁ、別にアイコンが表示されてなくても良かったんですが…ALT+Tabでも表示されてるし、表示してみるかと ;)

ウィンドウハンドルは前のエントリで取得できてるので、それから取得できるはず。で、調べてみるとSendMessageかGetClassLong辺りで取得できるっぽい。何で2種類あるんでしょうね :arrow:

とりあえず、SendMessageでアイコンを取得してみました。ありゃ、取れるアプリケーションと取れないアプリケーションがあるよ :shock:

仕方ないので、GetClassLongに変えてみました。う~ん、SendMessageより良い感じ。でも、やっぱり取得できないアプリケーションがある…結局よくわからないので両方の併せ技で取得するようにしましたとさ。

HICON hicon = HICON(::GetClassLong(hwnd, GCL_HICONSM));
if (hicon == NULL) {
    hicon = HICON(::SendMessage(hwnd, WM_GETICON, TRUE, NULL));
    if (hicon == NULL) {
        hicon = ::AfxGetApp()->LoadIcon(IDR_DEFAULTICON);
    }
}
    // ここで、hiconにアイコンが取得できてる

IDR_DEFAULTICONは、どうしてもアイコンが取得できなかった場合に使うアイコンリソースです。

う~ん、アイコン回りのややこしさも何とかならないものですかね :roll:

TrackBack URL :

ALT+Tabチックなプログラムを書く…切替タスク取得編

Windowsでタスク切替を行うショートカットキーと言えば、ALT+Tab系でコノ機能を拡張してくれるフリーのプログラムも結構あります。個人的にお薦めは、Alt-Tab Extender – Joeです ;)

でも、今回欲しかったのはWindowsの画面を飛ばしてWindowsCE側でタスク切替操作するのが前提。さらにフリーウェアも入れさせてくれないなどの理由から、ALT+Tabチックなプログラムを自前で実装してほぼ完成したんですが…画面飛ばしの某商用ソフトの機能で何とかなったので、結局陽の目を見ることはなくなっちゃいました :|

いわゆるチョンプロに近いものなんですが…結構面白かったので要点を少しづつ小分けにしてメモ。なお、開発環境はなんでイマドキって感じですが…VC6+MFCです(客先指定ですから) :arrow: 実行環境はXPと2003 Serverです。

とりあえず、タスク切替ですのでタスクを取得できなければお話になりません。なので、とにかくALT+Tabキーを押した時に表示されるのと同じものを取得してみます。

EnumWindowを使って、ウィンドウを列挙してそこから何とか合わし込めば良いだろうと思ったのですが…Google先生に訊いても書いてるページによって、少しづつ条件が異なってたりします。結局以下のような感じで切り替えるタスクのウィンドウをリストアップしました(少なくともXP、2003 Serverでは良さげです)。

BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
    HWND parent = ::GetParent(hwnd);
        // 親ウィンドウが居るものはリストアップしない
        // ただし、親がデスクトップのものはリストアップ対象とする
    if (parent != NULL && parent != ::GetDesktopWindow()) {
        return TRUE;
    }
 
    DWORD visible = ::GetWindowLong(hwnd, GWL_STYLE) & WS_VISIBLE;
    DWORD tool = ::GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_TOOLWINDOW;
    HWND owned = ::GetWindow(hwnd, GW_OWNER);
        // VISIBLE属性のものはリストアップ対象
        // TOOLWINDOW属性のものはリストアップ除外
        // OWNERウィンドウはリストアップ除外
    if (visible == 0 || tool != 0 || owned != NULL) {
        return TRUE;
    }
 
    TCHAR strWindowText[BUFSIZ];
        // ウィンドウタイトルの取得に失敗したらリストアップ除外
        // ウィンドウタイトルがないものもリストアップ除外
    if (::GetWindowText(hwnd, strWindowText, BUFSIZ) > 0) {
        // リストアップするウィンドウハンドルなのでhwndを保持する
    }
    return TRUE;
}
 
        // リストアップしたい時にEnumWindowを呼び出す
    EnumWindow(EnumWindowsProc, 0);

とりあえず、上記プログラムの条件でALT+Tabと同じに合わし込むことができました。

ちなみに自分自身はダイアログベースのアプリで、自分自身はリストアップされないようにTOOLWINDOW属性を付けてます。あと、タスクバーにも自身が表示されないようにOnInitDialogメソッドの中に以下のコードも書いてたりします。

    ModifyStyleEx(WS_EX_APPWINDOW, 0)

しかし、何も条件をつけないでウィンドウを列挙すると何もアプリケーションを起動してない時点で約300個近いウィンドウが列挙されるとは…Windows恐るべし。さすが、Windowsと名乗るだけのことはあります :mrgreen:

てか、色んなものを引きずって来てるのでWindowsのウィンドウには色んな属性はあるわ、ウィンドウを扱うAPIも混乱するほどあるし、トドメは拡張とか言ってExもあるし…ホントつくづく厭になりますね。

TrackBack URL :