カテゴリー別

お絵描き、デザイン

写真、動画関連ソフト

アメーバピグ専用ソフト

ホームページ関連

画像処理

スキャナー用

SEO 関連

お楽しみ

その他

過去ログ

2018年07月19日(木)

Windows API、表示スケールが変わると、テーマのハンドルが無効になります

写真閲覧ソフトのミルノ PC フォトフレーム の修正中。
現在、メニューを「表示スケール」に対応させる作業中です。

写真をミルノに!

で覚えてね。キラーン。

タイトルの通り、OS の表示スケールを
変えると、テーマのハンドルが無効になります。

テーマのハンドルとは、
OpenThemeData の返り値です。

ハンドルが無効になることは、
OpenThemeDataForDpi の方に書いてあります。

現時点では、何故か、関数プロトタイプの返り値が
void になってますが、HTHEME の間違いですね。

ハンドルが無効になるタイミングは、
WM_DPICHANGED メッセージでわかります。

このメッセージは、トップレベルの
ウィンドウにのみ届くみたいですなので、
そのタイミングで、ハンドルを開き直すか、
後で開き直すために、 CloseThemeData しましょう。

もし、描画速度が気にならないのであれば、
描画の度に、OpenThemeData して、
ハンドルをキャッシュしない
手もあるかもしれません。

ちなみに、自分の環境では、表示スケールを変えた後で、
HTHEME を開き直さずに、描いた場合、
描けたり、描けなかったりしました。

不具合が見つけづらいので、ご注意ください。

おまけ

ちなみに、 WM_THEMECHANGED メッセージが届いたときも、
HTHEME は無効となります。

このメッセージは子ウィンドウにも届くみたいなので、
HTHEME を使って描画するコントロールの
コードで対応できると思います。

・・・

日本語の最新版はこちらのページから、ダウンロードできます
You can download the latest version of Miruno PC Photoframe here.

x64 の最新版はこちらのページから、ダウンロードできます
Download the latest version of Miruno PC Photoframe x64 here.

・・・

月額会員専用のx64 版 もあります。
月額会員には、こちらのページから参加できます

・・・

例えば、Windows 10 の場合、ハイコントラスト
にしたときに、WM_THEMECHANGED が届きます。

この場合、オープン済みの HTHEME は無効となり、
テーマの機能も無効になるので、OpenThemeData
で開き直すと NULL になります。

ミルノ PC フォトフレーム
ミルノ PC フォトフレームのダウンロード
ミルノ PC フォトフレームの更新履歴
ご意見・ご要望連絡窓口


2018年07月17日(火)

Windows API、アイコンリソースに含まれる全てのアイコンのサイズを列挙する方法

写真閲覧ソフトのミルノ PC フォトフレーム の修正中。
現在、メニューを「表示スケール」に対応させる作業中です。

写真をミルノに!

で覚えてね。キラーン。

アイコンリソース (ICON) には、
複数のサイズの画像を含めることができます。

となれば、アイコンリソースに含まれている
全ての画像のサイズを列挙したくなるのが人情ってものですw。

アイコンリソースの画像のサイズを全て列挙する

まんまの Windows API は無いみたいなので、
アイコンリソースをロックして
メモリーを参照する必要があります。

FindResource して、
LoadResource して、
LockResource すると、
メモリーの内容が見れます。

解放する必要もないので、そんなに難しくはないです。

FindResource の lpType には、
RT_GROUP_ICON を指定します。

で、 The format of icon resources - The Old New Thing
にある GRPICONDIR* にキャストすれば OK です。

GRPICONDIRENTRY は、Icons にある
ICONDIRENTRY とは微妙に違うので注意です。

最後の、DWORD dwImageOffset が
WORD nId になってるので、
2 バイト少ないです。

ちなみに、構造体にパディングが入るとダメなので、
構造体の宣言の前で、
#pragma pack(1)
し、終わったら、
#pragma pack()
で、ディフォルトの値に戻してあげましょう。

ま、後は大丈夫と思いますが、アイコンの数は、
ポインターが GRPICONDIR* info だとすると、
info->idCount で取得できます。

各アイコンのサイズは、
info->idEntries[i].bWidth
info->idEntries[i].bHeight
ですね。

・・・

日本語の最新版はこちらのページから、ダウンロードできます
You can download the latest version of Miruno PC Photoframe here.

x64 の最新版はこちらのページから、ダウンロードできます
Download the latest version of Miruno PC Photoframe x64 here.

・・・

月額会員専用のx64 版 もあります。
月額会員には、こちらのページから参加できます

・・・

パネルを固定するピンボタンは、拡縮でぼやけさせたくないので、
アイコンリソースに含まれる画像サイズを列挙したいなー
と思ったら、結構大変でした。

アイコンに含まれる画像サイズは
既に知ってるわけだから、どこかに
配列で書いちゃえば楽ですね。

でも、そうすると、アイコンに含まれる
画像サイズのバリエーションを変更したときには、
配列も忘れずに書き替える必要がでてきます。

とはいえ、画像サイズのバリエーションを
一生変更しなかった場合、コーディングに無駄な時間
がかかるため、どちらがいいかは、わかりませんな。

ミルノ PC フォトフレーム
ミルノ PC フォトフレームのダウンロード
ミルノ PC フォトフレームの更新履歴
ご意見・ご要望連絡窓口


2018年07月13日(金)

Windows API、モニター毎の DPI に合わせてウィンドウのアイコンを更新する

写真閲覧ソフトのミルノ PC フォトフレーム の修正中。
現在、メニューを「表示スケール」に対応させる作業中です。

写真をミルノに!

で覚えてね。キラーン。

今日も、高 DPI 環境に対応するための処理を
コツコツと書いてました。なんとなく
予感していた通り、結構大変です。

今日は、ウィンドウキャプション
についての記事を書きますわ〜。

まず、ウィンドウキャプションを
モニター毎の DPI に対応させるには、
アプリケーションのマニフェストに、
Per-Monitor and Per-Monitor (V2) DPI Awareness
を追加すれば OK です。

V2 のマニフェストのサンプルは
下記ページにあったので、参考にしました。

Application Manifests | Microsoft Docs
Application manifest for Per Monitor V2 · GitHub

ただし、PerMonitorV2 は、Windows 10 でしか
認識されないので、Windows 8.1 とかで、
完全に Per-monitor 環境に対応するには、
キャプションを独自で描画する必要がありそうです。

話を戻して、Windows 10 の最新バージョンで
アプリを動かす場合は、V2 のマニフェストを
用意するだけでキャプションも正しく描画されるのですが、
場合によっては、左端のアイコンがぼやけます。

というわけで、ぼやけさせたくない場合は、
キャプションのサイズに合わせた、
アイコンに更新する必要があります。

キャプションのアイコンを更新する

メインウィンドウの DPI に変更が生じた場合、
WM_DPICHANGED メッセージが発生するので、
これのメッセージハンドラーでアイコンを更新します。

キャプションのアイコンのサイズは、
GetSystemMetrics に、
SM_CXSMICON、SM_CYSMICON
を指定すると取得できます。

が、起動時の (おそらくはプライマリーモニターの) DPI に
応じた値が返るので、補正する必要があります。

起動時の DPI は ↓ のようなコードで取得できます。

CWindowDC dc(NULL);
m_systemDpis.x = dc.GetDeviceCaps(LOGPIXELSX);
m_systemDpis.y = dc.GetDeviceCaps(LOGPIXELSY);

一方、現在の DPI は、
CPoint dpis(LOWORD(wParam), HIWORD(wParam));
で取得できます。

wParam は、WM_DPICHANGED のパラメーターです。

補正するには、現在の DPI をかけてから
起動時の DPI を割れば OK です。
newValue = ::MulDiv(value, dstDpi, srcDpi);
みたいなコードになります。

で、新しいサイズでアイコンをロードしてから
再設定すれば OK です。

例えば、 LoadImage 関数 の cxDesired、cyDesired
に新しいサイズを指定して読み込み直します。

最後に、メインフレームに WM_SETICON メッセージ
を送って、アイコンを更新します。

今、更新しているのは小さい方のアイコンなので、
wParam には ICON_SMALL を指定します。

大きい方のアイコンを更新する

キャプションには直接影響しませんが、
大きい方のアイコンも合わせて
更新しておいた方がいいかもしれません。

大きい方のアイコンを更新するには、
WM_SETICON の wParam には ICON_BIG を指定します。

で、アイコンサイズの取得には、
SM_CXSMICON、SM_CYSMICON のかわりに
SM_CXICON、SM_CYICON を使います。

後の処理は、だいたい同じです。

アイコンのリソースを更新する

まだ、ぼやける場合は、たぶんリソースの問題です。

LoadImage するリソースが ico ファイルの場合は、
いろいろなサイズの画像を含めておくと、ぼやけません。

例えば、ディフォルトの 16、32 の大きさだけでなく、
20、24、48、256 なんかも用意しておきましょう。

・・・

日本語の最新版はこちらのページから、ダウンロードできます
You can download the latest version of Miruno PC Photoframe here.

x64 の最新版はこちらのページから、ダウンロードできます
Download the latest version of Miruno PC Photoframe x64 here.

・・・

月額会員専用のx64 版 もあります。
月額会員には、こちらのページから参加できます

・・・

High DPI Desktop Application Development on Windows
に WM_DPICHANGED は、both the top-level and child
にくるって書いてあるけど、嘘っぽいな。

WS_CHILD の純粋な子には、来なかった。

top-level をオーナーに持つ
ポップアップウィンドウにはきたから、
そういう意味なのかもね?

ミルノ PC フォトフレーム
ミルノ PC フォトフレームのダウンロード
ミルノ PC フォトフレームの更新履歴
ご意見・ご要望連絡窓口


2018年07月10日(火)

Windows API、ウィンドウクリック時にアクティブ化しないようにする

写真閲覧ソフトのミルノ PC フォトフレーム の修正中。
現在、メニューを「表示スケール」に対応させる作業中です。

写真をミルノに!

で覚えてね。キラーン。

Windows API の TrackPopupMenu
モニター毎の DPI に対応していないので
自作のポップアップメニューを改良中です。

自作のポップアップメニューとは、
ウィンドウの描画やマウスメッセージの処理など、
全て自分のコードで行うものです。

で、今日困ったのが、自作のポップアップメニューを
クリックしたときに、メニューにフォーカスが来てしまう問題です。

フォーカスは、メニューを表示したときのまま、
メニューのウィンドウは取得しないのが正しい挙動です。

色々と試しましたが、うまくいった方法は次の通り。

フォーカスを阻止する方法

ポップアップウィンドウに届く、
WM_MOUSEACTIVATE メッセージに、
MA_NOACTIVATE を返します。

これだけで OK です。

ポップアップメニューは、オーナーウィンドウの
外に、はみだして表示する必要があるので、
必然的に、トップレベルウィンドウになります。

トップレベルウィンドウは、クリックすると、
ディフォルトの挙動ではアクティブになるので、
MA_NOACTIVATE で防ぎます。

フォーカスは、アクティブ化の副作用で発生するので、
アクティブ化を阻止すれば、フォーカスも発生しません。

その他の試した方法1

よくわかりませんが、ウィンドウの拡張スタイルに、
WS_EX_NOACTIVATE を設定する方法は効きませんでした。

効かなかった原因は不明です。

その他の試した方法2

WM_ACTIVATE で、メニューがアクティブ化したときに
元のウィンドウを、SetActiveWindow しても
一回アクティブになっちゃってるので、
フォーカスが発生しちゃいます。

その他の試した方法3

WM_SETFOCUS メッセージで、
元のウィンドウを、SetFocus すると
フォーカスを元に戻せますが難点があります。

元のフォーカス先のウィンドウ (のルート) がアクティブ化し、
最前面にくるので、メニューのウィンドウが
z オーダー的に、後ろに隠れちゃいます。

SetFocus した後、むりやり z オーダー
を調節できますが、ちらつきます。

メニュー表示元のウィンドウが
「最前面」で無い場合は、メニューを
最前面にするとちらつきを抑制できますが、
表示元が「最前面」の場合は回避不能です。

また、フォーカスが一瞬は移動するので、
フォーカスのあるなしで描画が変わる
ウィンドウも、ちらつきます。

例えば、ツリービューはフォーカスがある状態では
選択項目が「青色」ですが、フォーカスが無いと
「灰色」になるため、ちらつきます。

おまけ

トリッキーな方法を使うと、
フォーカスを戻したウィンドウの後ろに
メニューが一瞬隠れる「ちらつき」は回避できました。

その方法は、フォーカスを戻す先のウィンドウの
トップレベルウィンドウのウィンドウプロシージャーで、
WM_WINDOWPOSCHANGING メッセージの処理をいじります。

具体的には、ポップアップメニューをクリックした場合のみ
SWP_NOZORDER フラグを立てて、z オーダーの変更を阻止します。

ただ、この方法はフォーカスの戻し先の
ウィンドウプロシージャーをいじる必要があるので、
あまり、よい解決方法にはならないでしょう。

・・・

日本語の最新版はこちらのページから、ダウンロードできます
You can download the latest version of Miruno PC Photoframe here.

x64 の最新版はこちらのページから、ダウンロードできます
Download the latest version of Miruno PC Photoframe x64 here.

・・・

月額会員専用のx64 版 もあります。
月額会員には、こちらのページから参加できます

・・・

WM_SETFOCUS のところで
なんとかしようとしてたら、
無駄に、時間かかったわー。

ミルノ PC フォトフレーム
ミルノ PC フォトフレームのダウンロード
ミルノ PC フォトフレームの更新履歴
ご意見・ご要望連絡窓口


2018年05月21日(月)

iso イメージを Windows API でマウントする実験

バッチファイルとかで、iso イメージをマウントしたくなったので、
Windows API でテストコードを書いてみました。

まず、ドライブレターを指定せずに
マウントするのは比較的簡単にできます。

iso ファイルを、OpenVirtualDisk して、
AttachVirtualDisk すれば OK です。

CVirtualDisk vd;
VIRTUAL_STORAGE_TYPE vt;
vt.DeviceId = VIRTUAL_STORAGE_TYPE_DEVICE_ISO;
vt.VendorId = VIRTUAL_STORAGE_TYPE_VENDOR_UNKNOWN;

DWORD ret = vd._OpenVirtualDisk(
  &vt, parser.ImagePath().c_str(),
  VIRTUAL_DISK_ACCESS_ATTACH_RO
  | VIRTUAL_DISK_ACCESS_DETACH
  | VIRTUAL_DISK_ACCESS_GET_INFO
  ,
  OPEN_VIRTUAL_DISK_FLAG_NONE,
  NULL
);
ATLASSERT(ret == 0);

ATTACH_VIRTUAL_DISK_PARAMETERS avdp;
avdp.Version = ATTACH_VIRTUAL_DISK_VERSION_1;

ret = vd._AttachVirtualDisk(
  NULL,
  ATTACH_VIRTUAL_DISK_FLAG_READ_ONLY
  | ATTACH_VIRTUAL_DISK_FLAG_PERMANENT_LIFETIME,
  0,
  &avdp,
  NULL
);
ATLASSERT(ret == 0);

CVirtualDisk は HANDLE をラップする自作のクラスです。
デストラクターでクローズハンドルするのが主な役割です。

一方、ドライブレターを指定してマウントするのは結構大変です。

ATTACH_VIRTUAL_DISK_FLAG_PERMANENT_LIFETIME のところに、
| ATTACH_VIRTUAL_DISK_FLAG_NO_DRIVE_LETTER を追加すると、
ドライブが割り当てられなくなるので、自分で割り当てます。

SetVolumeMountPoint でドライブを割り当てるのですが、
管理者権限で呼び出さないと失敗します。

また、SetVolumeMountPoint に渡す、
lpszVolumeName の取得も結構大変です。

OS のディスクの管理画面では、ドライブレターの変更が
管理者権限でなくともできるので何か方法があるはずと
思って調べてみると下記ページを見つけました。

Inside Mountvol.exe - CodeProject

・・・

なんか、大変そう。

ご意見・ご要望連絡窓口


2018年04月19日(木)

Gdiplus 矩形と円の描画、AlphaBlend などの速度を計測してみた

SVG エディター ストローク でたくさん制御点を描画したときに、
重いよーな気がしたので、色々とテストしてみました。

Gdiplus の DrawLine で矩形を描画したときの速度

DrawRect_10 109
DrawRect_20 141
DrawRect_40 219
DrawRect_80 390
DrawRect_160 734
DrawRect_320 1422

例えば 1 行目。
_10 は、10 x 10 ピクセルの矩形を
10000 回描いた場合の時間 (ミリ秒) です。

矩形なので 1 回ごとに、
DrawLine が 4 回呼ばれます。

描画先は、32 bpp の DIB から作成した Graphics。
SetPixelOffsetMode(PixelOffsetModeHighQuality);
SetSmoothingMode(SmoothingModeHighQuality);
な感じ。まぁ、だいたい 2 倍ずつ時間が増えてますね。

次に、Gdiplus の DrawEllipse で円を描画したときの速度

DrawCircle_10 187
DrawCircle_20 297
DrawCircle_40 500
DrawCircle_80 718
DrawCircle_160 1297
DrawCircle_320 2313

やはり、DrawLine と似た傾向ですが、
やや複雑な分、ちょっと時間がかかりますね。

で、何度も描く、(小さな) 図形の場合は
画像にしておいて、アルファブレンドしたら
速くなるのか、テストしてみます。

AlphaBlend_10 109
AlphaBlend_20 110
AlphaBlend_40 156
AlphaBlend_80 281
AlphaBlend_160 781
AlphaBlend_320 2609

こちらは画像を全部参照するので、
長さが 2 倍になると処理量は 4 倍になります。

320 > 160 は 1 / 4 に近いといえなくもないですが、
それ以外では、全然 1 / 4 になってません。

小さい画像を AlphaBlend する場合は、もっと速くていいはず。
なので、適当に書いた自前の AlphaBlend でテストしてみます。

OwnAlphaBlend_10 0
OwnAlphaBlend_20 32
OwnAlphaBlend_40 141
OwnAlphaBlend_80 531
OwnAlphaBlend_160 2172
OwnAlphaBlend_320 8609

やはり、_10 とか _20 だと速いですが、
逆に、80 以上では、遅いです。

AlphaBlend はセットアップに時間がかかる一方、
データー処理は高速になるような方法を使ってますね。

グラフィックスカードの機能を
使ってるのかもしれません。

ま、そんなわけで、比較的小さな画像を
別の画像に合成するには、自前の
AlphaBlend で描くのが速そうです。

・・・

一応、勘違いのないように補足しときます。

「小さい画像をたくさん描く場合、
グラフィックスカードの描画を使わない方が速い」

ような結論に見えますが、そうじゃないです。

AlphaBlend ではおそらく
グラフィックスカードの何らかの初期化と
クリーンナップが毎回行われているため遅くなっているだけです。

通常、グラフィックスカードの機能で画像を描く場合、
初期化、描画、クリーンナップの指示をした後で
一気に処理するため、初期化の時間はあまり影響しなくなります。

なので、グラフィックスカードの性能をきちんと引き出せば
普通は、CPU による処理より、速くなります。

ま、あくまで一般論ですけど。

・・・

あ、あと、同じ画像を何回も参照してるから、
CPU のキャッシュが、よく効いてます。

違う画像を次々に描く場合は、
もっと、遅くなるでしょうねー。

ストローク
ストローク ダウンロード
ストローク サンプル画像
ストローク 更新履歴
ご意見・ご要望連絡窓口


2018年04月03日(火)

WinMain から gtest する方法

SVG エディター ストローク の単体テストは
別のプロジェクトでビルドしていたのですが
二度手間がひどいので統合しました。

ストロークはウィンドウアプリケーション、
一方、単体テストは、gtest を利用しているので
コンソールアプリケーションになります。

作成するアプリケーションのタイプが違うので
別のプロジェクトに分けるのが自然ですが、
無駄に手間がかかるので統合しました。

プロジェクトを分けると、
.cpp や .h ファイルをそれぞれに
追加する必要があって面倒なうえ、
それぞれのプロジェクトで同じファイルを
コンパイルすることになるので時間もかかります。

単体テストとアプリケーションの両方から使う
共通のコードを、まとめた DLL、もしくは lib
を作成するプロジェクトを新たに作成し、
リンクする方法もありますが、
それはそれで面倒です。

なので、一つのプロジェクトを使い、
コンパイルオプションによって
生成されるアプリケーションを
分けることにします。

基本的には、

#define TEST_MODE

#ifdef TEST_MODE
#else
#endif

的なコードで、コンパイルする
コードを分岐していきます。

で、最初に、_tWinMain と _tmain を
コンパイルオプションで切り替えてみたのですが、

error LNK2019: 未解決の外部シンボル _WinMain@16 が関数 ___tmainCRTStartup で参照されました。

的なエラーになってダメでした。

コンパイルオプションを変えればいけそうですが、
新しいビルドの構成とかするのは、面倒なので却下デス。

しょうがないので、入り口は、_tWinMain のままいきます。

コンソールアプリ用のコマンドライン引数

コマンドライン引数は、 __argc, __argv, __wargv
を使えば OK なので簡単です。

ただし、ユニコードアプリの場合は、
__argv は NULL になるので __wargv を使いましょう。

コンソールを用意する

あとは、コンソールを用意します。

自分のコードを見ると、 AttachCondole に失敗した場合、
AllocConsole してます。たぶん、コンソールからアプリを
起動したときのことを想定してるっぽいです。

で、成功したら、_fileno(stdout) とかが負の場合
freopen_s してます。ファイル名は、CONOUT$ です。

ちなみに、stderr のファイル名は、CONOUT$
stdin のファイル名は、CONIN$ みたいです。
↓ ま、こんな感じです。

if (_fileno(stdout) < 0)
  m_stdout.Reopen("CONOUT$", "w", stdout);
if (_fileno(stderr) < 0)
  m_stderr.Reopen("CONOUT$", "w", stderr);
if (_fileno(stdin) < 0)
  m_stdin.Reopen("CONIN$", "r", stdin);

↑ の自分のコードですが、
そのままはコンパイルできないので、
てきとーに、freopen_s にでも
書き替えてくださいな。

AttachConsole とか、AllocConsole に成功してる場合は、
プログラム終了前に FreeConsole する必要があるみたいですね。

あ、コンソールに日本語を出したい場合は、

std::wcout.imbue(std::locale("", std::locale::ctype));
std::wcerr.imbue(std::locale("", std::locale::ctype));

とかした方がいいかもね。

gtest の呼び出し

あとは、普通に gtest を呼びだせば OK です。

::testing::InitGoogleTest(&__argc, __wargv);
int ret = RUN_ALL_TESTS();

ま、こんな感じか。

ストローク
ストローク ダウンロード
ストローク サンプル画像
ストローク 更新履歴
ご意見・ご要望連絡窓口


2018年02月27日(火)

StackWalk64 が何故かおかしな値しか返さない不具合の修正方法

だいぶ前にコーディグした
スタックトレースを取得するコードが
うまく動いていなかったので修正しました。

スタックトレースは、 StackWalk64 が 非0 を返すまで呼べば
取得できるのですが、何故か 1 コか 2 コしか返さないうえ、
関数名を取得してみると、よくわからないものが入ってます。

コードにおかしなところが無さそうだったので、
サンプルコードでも探してみようと思って
検索をかけてみると、原因がわかりました。

StackWalk64 の使い方はココ にあります。
英語ですが、読めば使い方がわかると思います。

で、StackWalk64 がおかしな値を返す原因は、
カレントスレッドのコンテキストの取得に、
GetThreadContext を使っているところにありました。

GetThreadContext をよく読むと確かに、
「GetThreadContext をカレントスレッドに対してコールすると、
 成功しますが、得られるコンテキストは、無効です」
とありますね。

・・・

なんでやねん。そんな仕様あるかよ^^。

で、ココ にあるように、Win32 ではアセンブラのコード、
x64 では、RtlCaptureContext を使うことで、
正しいアドレスが取得できるようになりました。

・・・

ちなみに、スタックトレースというのは、
関数呼び出しの入れ子情報のことです。

例えば、main 関数から a() を呼びだし、
a() の中で b() を呼びだしたときの
スタックトレースは、main > a > b
みたいな感じになります。

スタックトレースはデバッガーで
停止すれば見られるのですが、
スタックトレースをコードで取得すると
ログに吐いたり、ある時点でのトレースを
後から見たりできて便利です。

ちなみに、今回スタックトレースを使いたくなったのは、
ログにスタックトレースを吐きたかったからです。

具体的には、 ローカルブラウザ の閲覧履歴に変更があったときの
デバッグ用のログに、スタックトレースも出力することで
デバッグしやすくしました。

ローカルブラウザ は自分のパソコンに保存した
html や xml を開きやすくしたウェブブラウザーです。

気になる方は、試してみてくださいね!

ローカルブラウザ
ローカルブラウザのダウンロード
ローカルブラウザの更新履歴
ご意見・ご要望連絡窓口


2018年02月16日(金)

c、c++ 浮動小数点の計算に注意

写真閲覧ソフトのミルノ PC フォトフレーム
の新機能の実装がだいたい終わったので、テスト中です。

写真をミルノに!

で覚えてね。キラーン。

今日、直した不具合で次のようなものがありました。

double speed = speedPerSec / refreshRate;

speeedPerSec と refreshRate は DWORD 型です。
わりと、やりがちですが、
初心者だと、はまる可能性ありです。

上の式は一見 speedPerSec が 1
refreshRate が 2 だと、
speed に 0.5 が入りそうですが、
結果は 0 です !

何故 0 になるかというと、
speeedPerSec と refreshRate は DWORD 型なので、
DWORD 型の割り算が行われた後で、
double 型に変換される仕様だからです。

もちろんプログラミング言語の仕様によっては、
0.5 になる場合もありますが、c、c++ では、0 です。

こういうのは、プログラムの式を
数学の式と同じように考えていると
気付かないので注意が必要です。

修正するには、

double speed = speedPerSec;
speed /= refreshRate;

とか、

double speed = (double)speedPerSec / refreshRate;

のようにします。

日本語の最新版はこちらのページから、ダウンロードできます
You can download the latest version of Miruno PC Photoframe here.

x64 の最新版はこちらのページから、ダウンロードできます
Download the latest version of Miruno PC Photoframe x64 here.

・・・

月額会員専用のx64 版 もあります。
月額会員には、こちらのページから参加できます

経験をつむと、間違いの頻度もおちるし、
間違いにもすぐ気付くようになりますが、
間違わないようにはなりませんなぁ。残念!

ミルノ PC フォトフレーム
ミルノ PC フォトフレームのダウンロード
ミルノ PC フォトフレームの更新履歴
ご意見・ご要望連絡窓口


2018年01月19日(金)

7z.dll を使ってみる段階は完了しました

7z.dll を使って書庫を解凍してみるテストが完了しました。

安定して使えそうな感じでなので、
使いやすくラップする作業に入りました。

真面目にやると大変ですが、
使う API しかラップしないので
そんなに、かからないでしょう。

ちなみに、ラップとは
サランラップをかけること
と似たようなもんで、かけると
食材をつかんでも汚れなくなるので安心です。

やっぱ、違うか。

ま、雰囲気は似ていて、直接さわるよりも
使いやすくなるようにします。それがラップ。

当然、うまくやらないと、
使いにくくなるだけなので意味ないです。

7z.dll の場合、COM なので、
ATL の CComPtr を使うと
かるくラップできます。

私の場合、エラー処理のコードを隠したいので、
HRESULT 値がおかしいときは例外を
投げるようなコードでさらにラップします。

ちなみに、PROPVARIANT のラッパーも
ATL/WTL にないみたいなので自前でラップしてます。

・・・

話は変わりますが、7z.dll を ATL で扱うには

struct __declspec(uuid([GUID])) IArchiveOpenCallback;

みたいな宣言が必要です。上の疑似コードは、
IArchiveOpenCallback の GUID として
[GUID] を紐付けます。

error C2787: 'IArchiveOpenCallback':
このオブジェクトに関連付けられた GUID はありません。

みたいなエラーになったら宣言してあげましょう。

ミルノ PC フォトフレーム
ミルノ PC フォトフレームのダウンロード
ミルノ PC フォトフレームの更新履歴
ご意見・ご要望連絡窓口


| 1/5PAGES | >>