ドナドナされるプログラマのメモ

Windows用アプリのプログラミングメモ

Critical error detected c0000374

昔作ったソフトの改造をしていたら、突然「Critical error detected c0000374」というエラーが出て止まるようになった。実行継続して例外を処理させてみたら、

「ハンドルされない例外が 0x00007FFB1E01E6FC (ntdll.dll) で発生しました(伏せ字.exe 内): 0xC0000374: ヒープは壊れています。 (パラメーター:0x00007FFB1E0722B0)。」

なんてダイアログが出てきた。ヒープ破損!?メモリ関係でやっちゃったかなあ・・・。とりあえず、stdafx.hに

#include <crtdbg.h>

を追加。そして、プログラムが停止したあたりに

_ASSERT(_CrtCheckMemory());

を仕込み、ヒープを破壊した箇所を絞り込む。・・・?なんでこんなコードで破壊が起きているんだ?

 ちょっとだけコード解説。このコードは、CImageクラスの画像をOpenCVのMatクラスにコピーしている。最初の数行で、それぞれに対し同一サイズの画像用メモリを確保し、memcpyでコピーしている。GetPitch()でmemcpyの仕方を場合分けしているのは、CImage型の変数が有する画像イメージへの生ポインタを取得するGetBits()関数が2通りのポインタを返すためだ。

CImageは、画像左上を原点とするフォーマットと左下を原点とするフォーマットをサポートする。GetPitch()やGetBits()は、ユーザーがその違いを気にしなくても済むよう、左下原点の場合はPitchとして負の値を、GetBitsの結果として左下の点に相当するメモリアドレスを返す。これにより、たとえばforループを書くときに場合分けをせずに済むようになる。しかし、この機能は今回のコードでは邪魔で、それぞれの場合用に書き分ける必要が生じる。それが、GetPitch()でmemcpyの仕方を場合分けしている理由だ。

さて、本題。同一サイズの画像をコピーしているだけなのに、なぜヒープが壊れるのだ?・・・もしかして、画像サイズは同一でも、メモリサイズは同一ではない?試しに、1ラインあたりのメモリサイズを見てみよう。CImageもcv::Matも、構造体内にデータとして持っていたはず・・・

  • CImage
    img.m_nPitch : -408
  • cv::Mat
    *tmp.step.p: 405

ビンゴでした。1ラインあたりのメモリサイズが異なっていました。CImage::GetPitch()のドキュメントにも、「The pitch can also include additional memory, reserved for the bitmap.」なんて書いてありました。これを直せば、治るかな?

艦これで備蓄しておきたい装備数

艦これ、保有装備枠きつい。でも、レア装備を廃棄するのは怖い。使うかもしれないし。

・・・本当に使うかな?使うとしたらいくつだろう?

ということで、必要な数がいくつか考察&メモ。なお、必要数はプレイスタイルに依存するので、これはあくまでも自分の場合です。

対潜水艦装備

潜水艦に対する装備は、1艦隊分あれば充分そう。連合艦隊でも、潜水艦に攻撃するのは第2戦隊だけですし。対潜装備が3枠/艦、とすると、1艦あたり水中探信儀×2、三式爆雷投射機×1かな。水中探信儀は、艦のLVが充分あると仮定すると、攻撃力の有る四式水中探信儀優先で。

ということで、必要な装備数は以下の通り。

  • 三式水中探信儀、四式水中探信儀×12
  • 三式爆雷投射機×6

水上電探

大型艦用と小型艦用で分ける。

連合艦隊でも、大型艦はせいぜい8隻。でも支援艦隊には4隻×2いるかもしれない。1隻につき1個必要とすると、合計16個。

一方、小型艦は連合艦隊だと12隻ありえそう。支援艦隊は2隻×2かな。合計・・あら、こちらも16だ。

  • 32号水上電探×16
  • 33号水上電探×16

対空電探

大型艦用と小型艦用で分ける。

連合艦隊でも、大型艦はせいぜい8隻。支援艦隊に装備することは無い。1隻につき1個必要とすると、合計8個。

一方、小型艦は連合艦隊だと12隻ありえそう。合計12。

  • FuMO、14号対空電探×8
  • 13号対空電探改×12

 艦載機

艦隊、支援艦隊には、最大でもそれぞれ空母4とする。

戦闘機は、空母4隻に各3スロ搭載、陸上基地に4スロ×4配備すると合計28機。多いな。

艦爆は、支援×2と艦隊のみ、陸上配備なしとし、艦隊は各3スロ、支援は各4スロとすると3×4+4×4×2=12+32=44機。多いな。

艦攻は、艦隊のみとして、艦隊は各3スロだと12機。リーズナブルだ。

偵察機は、連合艦隊のみに必要として、6+3=9機。

水上機は、航空戦艦と航空巡洋艦に載せるとしてもせいぜい6隻で、1隻あたり2スロとすると12機。

  • 烈風とその仲間たち×28
  • 星一二型×44
  • 流星改×12
  • 零式水上観測機×9
  • 瑞雲系×12

主砲

20cm系主砲は、連合艦隊考慮しても9隻×2スロ=18。

46cm系主砲は、連合艦隊(5隻?)とか支援を考慮するより、搭載艦考慮したほうが良さそう。せいぜい8ぐらい?

10cm連装高角砲+高射装置は、連合艦隊(12隻)と支援(2×2隻)を考えると、32欲しい。

他、色々ある気がするけど省略。

  • 20.3cm(2号)連装砲×18
  • 46cm砲×8
  • 10cm連装高角砲+高射装置×32

その他

ドラム缶について。遠征系は、 北方鼠:1個×4隻、東急1:1個×5隻、東急2:2個×5隻。連合艦隊で3スロ×6隻としても18。連合艦隊+東急1,2としても33個あればOK。

三式弾は連合艦隊考慮で9隻×1スロ=9個。

  • ドラム缶×33
  • 三式弾×9
  • 一式徹甲弾×9

とりあえずは以上かな?

OpenCVのmatchTemplateがうまく動かない!

 以下のコードが上手く動かず、しばし悩む。

まったく同じ画像のはずなのに、どうしてもminMaxLocの結果が0.85になる。なぜだ。そこで、各画像のメモリを覗いてみた。

 まずはイメージの探索対象側。イメージサイズは2×4, 32bit。0xf0f0f000 というパターンが7回続いた後に0x00000000が来ている。

f:id:donadonasan:20161022185535p:plain

次に、探索イメージ(pattern)。こちらもイメージサイズは2×4, 32bit。

f:id:donadonasan:20161022185930p:plain

なんと、こちらは0xf0f0f0ffというパターンが続き、その後0x000000ffが来ている。各ピクセルの4バイト目が、両者で食い違っていたのだ。OpenCVのmatchTemplateって、アルファチャンネルをサポートしていないから、結果に影響しないはずなんだがなあ。でも、影響するなら仕方ない。

もう少し調べてみたところ、探索対象側はMFCのCImageで作成されており、探索イメージはOpenCVにより作成していることがわかった。どうやら、両者でアルファチャンネルのデフォルト値が異なっているようだ。

そもそも、なんでアルファチャンネルを使っていないのに、使うコードになっているのだろう?元コードを書いた5年前の自分に聞いてみたいが、そんなことはできない。おそらく、CImageに関係する自分の8年ぐらい前のコードがアルファチャンネルを使っていたから、とかそんな理由だと思うが・・・。

ってわけで、ピクセル辺り32bitだったものを24bitのアルファチャンネルを使わないコードに書き換えてみた。その結果、無事minMaxLocの結果が1.0に。問題解決。

Windows10でバッチファイルをスタート画面にピン留めする

Windows10のスタート画面に拡張子が.batの所謂バッチファイルをピン留めしようとして苦戦したので、メモ。

セキュリティ的な理由からか、Windows10ではバッチファイルをスタート画面にピン留め出来ない。

f:id:donadonasan:20160822174926p:plain

図:バッチファイルを右クリックした時のメニュー。「スタート画面にピン留めする」が無い。

バッチファイルへのショートカットも同様にピン留めできない。なんてこった。

でも、なんとかする方法はある。バッチファイルを実際に実行しているcmd.exeへのショートカットにしてしまうのだ。これなら、実行ファイルへのショートカットとなり、ピン留め可能となる。以下に手順を示す。

  1. バッチファイルへのショートカットを作成する。
  2. ショートカットのプロパティを表示する。
  3. リンク先の先頭に、「cmd /c」を挿入する。

それぞれの手順を、以下に図入りで説明する。

続きを読む

サムスン Galaxy SC-04E 工場テストモード

手元のスマホを照明のリモコンにしようと思いたったのだが、赤外線でどんなコードを出せばいいのか分からない。「スマホに赤外線通信機能があればデコードできるかな?」と思ったけど、残念ながら手元のスマホサムスン製。送信機能しかないようだ。となると、解決策は3つ。

  1. 赤外線通信機能を持つガラケーで解析
  2. 赤外線を受光可能な装置を自作
  3. スマホの照度センサを使って解析

ハードウェアが揃っているという点では1.がベストだが、はたして自作プログラムは載せれるのか疑問である。3.の照度センサは時間応答性に疑問が。何しろ、赤外線通信は2kbpsぐらいの速度が出てるのだ。せいぜい1Hz程度の応答性があればいい照度センサで解析できるのか、やはり疑問である。となると、ソフトと回路にハードルがある2.か・・・。

しかし、3.はちょっと捨てがたい。そこで、照度センサの値を見てみることにした。

自分が使っているサムスンのGalaxy SC-04Eには工場テストモードがあり、このモードに入ることで各センサの値をリアルタイムに見ることができる。

テストモードへは、標準の電話をかけるアプリで「*#0*#」と入力すればよい。電話をかける必要は無い。なお、この情報は以下のサイトから入手。

All Secret Codes of Samsung Galaxy S4 | Tutorials

以下、工場テストモードにして様子を見た結果。

 

f:id:donadonasan:20160326193937p:plain

図:入力イメージ。このあと#を打つと自動的に次の図の状態になる。

 

f:id:donadonasan:20160326193944p:plain

図:工場テストモード。色々見れる。

 

f:id:donadonasan:20160326193947p:plain

図:"Sensor"を押した場合、このようなセンサ状態表示・テスト画面に遷移する。

 

f:id:donadonasan:20160326193951p:plain

図:Lights sensorを押すと、このような画面に遷移する。

 

見た感じ、10Hz以上の速度で値が更新されているように見えるけどどうだろう・・・。期待薄ではある。

バグフィックス祭り

片道9時間の長距離飛行中、ReadMeを更新するために艦むすリストメーカーを動かしていたら、バグを5個も見つけてしまった。久しぶりにプログラミングする時間も確保できたので、さくさく修正。そろそろver.2.0を名乗ってもいいかな?

2017/05/07追記:肝心のソフト入手ページを書き忘れていた。

公開ページ:

github.com

 

ソフトへの直接リンク:

https://github.com/nibasya/KanmusuListMaker/blob/master/%E9%85%8D%E5%B8%83%E7%94%A8/KanmusuListMaker2.0.zip?raw=true

続きを読む

CListBoxのスクロール制御

CListBoxに、垂直スクロールバーが表示される程度にアイテムが表示されている状態でAddStringやDeleteStringを実行すると、スクロールバーの位置がリセットされ最上位に戻ってしまうことがある。これは、リストボックスの操作をするときに困る挙動だ。

f:id:donadonasan:20160209013102p:plain

これを解決するには、AddStringやDeleteStringをする前にスクロールバーの位置を保存し、処理後にスクロールバーの位置を再設定すれば良い。スクロールバーの位置は、以下の関数で取得・設定できる。これらは、正確には一番上に表示されているアイテムの番号を取得・設定する関数である。

int CListBox::GetTopIndex();

int CListBox::SetTopIndex(int nIndex);

なお、余計なスクロールを抑制するため、以下も併用する。

void CWnd::SetRedraw(BOOL bRedraw = 1);

以下、サンプルコード。