カテゴリー別

お絵描き、デザイン

写真、動画関連ソフト

アメーバピグ専用ソフト

ホームページ関連

画像処理

スキャナー用

SEO 関連

お楽しみ

その他

過去ログ

2017年09月25日(月)

静的変数の初期化タイミング

今日は、ピグアイランドタイマー
Visual Studio 2015 でコンパイルできるように修正してました。

で、静的変数のリストに要素を追加して、
後で使おうとしたら、空っぽだったので、ビックリしました。

こういう場合、よくあるのは、
同じものに追加してるつもりが
別のものに追加している間違いです。

確認するには、追加してる場所と、
使おうとして空になっている場所の
双方でブレークして、変数のメモリーアドレスを
比較するのが速いです。

今回は変数名が g_soilItems なので、
&g_soilItems をウォッチすれば OK。

・・・

同じですね。

ということは、追加した後
どこかでクリアーしてしまってるのかな
と思って、g_soilItems で検索してみても
空にしてる個所はありませんでした。

あり???

あ、ひょっとして静的変数の初期化のタイミングかも。

で、リストに追加するコードの実行を
遅らせてみると、無事直りました。まじか。

今回のエラーが起き条件は以下の通り。

静的にリンクするライブラリーで、
静的なリスト変数を定義。

ライブラリーをリンクするアプリケーションプログラムでも
静的変数を用意して、その変数のクラスの
コンストラクターで、静的なリスト変数に項目を追加です。

この場合、静的なリスト変数が先に初期化されれば
問題無いはずなので、おそらく、項目に追加するための
クラス変数が初期化された後で、静的なリスト変数が
初期化されたんだと思います。

うーん。なんかしらのエラーが発生しないもんかのー。不思議。

まぁ、そんなわけで、静的なグローバル変数の
初期化タイミングには気をつけた方がいいですね。

ブログ著者のホームページはこちら です。


2017年09月22日(金)

HEAP CORRUPTION DETECTED エラーの修正

今日は、メディアからファイルを移動するノ
Visual Studio 2015 でコンパイルできるように修正してたら、
HEAP CORRUPTION DETECTED エラーが発生しました。

assert した場所のソースを見ると確保した
メモリーサイズを超えて書いちゃってるみたいです。
バッファーオーバーランってやつですね。

プログラム終了時の delete で落ちてたんですが、
それだと、どこらへんがおかしいのかわからんので
とりあえず、_CrtCheckMemory しまくる作戦にでました。

ATLASSERT(_CrtCheckMemory());

原理的には、1 行置きに _CrtCheckMemory すれば
メモリーが壊れた場所が特定できるわけですな。

今回の場合は、あやしい個所がある程度、特定できてたので、
2 分探索的に、トラップをしかけていくと 1 行が特定できました。

で、不具合の原因は、静的リンク用のライブラリーのコンパイル時と、
アプリケーションのコンパイル時とで、NOTIFYICONDATA 構造体
のサイズが違うのが原因でした。

↓ 例えば、ヘッダー (.h) は、こんな感じで、

class CShellNotifyIcon
{
  CShellNotifyIcon();
protected:
  NOTIFYICONDATA m_data;
};

↓ 実装 (.cpp) がこんな感じだと、

CShellNotifyIcon::CShellNotifyIcon()
{
  ::ZeroMemory(&m_data, sizeof(NOTIFYICONDATA));
}

あんまり、よくないです。

というのも、上記のコードをコンパイルするときと
アプリケーション (それを使う側) をコンパイルするときの
_WIN32_WINNT 等が違う場合、ヘッダーは両方のコンパイル時に
解釈されるので、構造体のサイズが、コンパイル毎に変わります。

結果、アプリケーションをコンパイルしたときの、
NOTIFYICONDATA サイズが小さい場合は、
バッファーオーバーランになります。

.cpp ファイルの sizeof(NOTIFYICONDATA) はライブラリ
コンパイル時のサイズですが、ヘッダーで定義されている
NOTIFYICONDATA はアプリのコンパイル時のサイズになるからです。

簡単に解決するには、ライブラリーとアプリケーションで
完全に _WIN32_WINNT 等を一致させることですが、
あまりよい解決法ではありませんね。

普通に、間違えるのが人間だし、全てのアプリケーションの
ターゲット OS を同じにできるとは限らないからです。

・・・

まぁ、いい解決方法は 2 つくらいあるかな。

1 つは、アプリケーションコンパイル時の
sizeof(NOTIFYICONDATA)
をライブラリーに渡して賢く処理する方法。

もう 1 つは、アプリケーションコンパイル時の
NOTIFYICONDATA の定義は絶対に使わない方法です。

後者は例えば、ヘッダーでは、std::vector m_data
みたいなサイズ可変のデーター領域を定義しておいて、
.cpp で m_data.assign(sizeof(NOTIFYICONDATA), 0);
みたいにして使えば、ライブラリーコンパイル時の
定義のみに依ったコードにできますね。

ブログ著者のホームページはこちら です。


2017年09月19日(火)

Visual Studio 2005、error LNK2019: 未解決の外部シンボル __vsnwprintf

下記エラーが発生したときの対処方法です。

1>DxErr.lib(dxerrw.obj) : error LNK2019: 未解決の外部シンボル __vsnwprintf が関数 "long __stdcall StringVPrintfWorkerW(unsigned short *,unsigned int,unsigned int *,unsigned short const *,char *)" (?StringVPrintfWorkerW@@YGJPAGIPAIPBGPAD@Z) で参照されました。

DxErr.lib のリンク時に発生しますが、同様のエラーは
他のライブラリーでも発生する可能性があるでしょう。

DxErr.lib で使用されている StringVPrintfWorkerW 関数が、
Visual Studio 2015 でリンクされる標準ライブラリーには
含まれていないために発生します。

解消するには、エラーの発生するプロジェクトのプロパティの
構成プロパティ > リンカー > 入力 ページ内にある
追加の依存ファイルに、legacy_stdio_definitions.lib を追加します。

もちろん、プラグマで指定しても OK です。

#pragma comment(lib, "legacy_stdio_definitions.lib")

・・・

前に別のプロジェクトをビルドするときにも発生したのですが
直し方を忘れてて、また調べ直しちゃったわ。

ブログ著者のホームページはこちら です。


2017年09月15日(金)

fatal error LNK1241: リソース ファイル XXX.res は既に指定されています

静的リンク用ライブラリーのプロジェクトにリソースファイルを
追加したら、ブログタイトルのエラーが発生しました。

ググると静的リンク用ライブラリーに
rc ファイルを 2 つ以上追加すると、
発生するみたいですね。

Resources in static library question

読めばわかりますが、プロジェクトのプロパティを開き、
リソース > 全般 ページにある「カルチャ」「リソースファイル名」
を空にすると直るとかいてあります。

で、自分の環境でも、直りました。
Microsoft Visual Studio Community 2015 です。

・・・

お試しあれ。

ブログ著者のホームページはこちら です。


2017年08月18日(金)

簡単な XML を読み書きするクラス

今日は簡単な xml を書いたり
読んだりするコードを書きました。

真面目にやるには、IXMLDOMNode とかを使うとよいのですが、
あまりにも簡単な XML の読み書きに使うのも、
何だな〜 と思って、てきとーなクラスを書いてみました。

↓ こんな感じ。

class CSimpleXmlWriter : public CSimpleXmlParser
{
public:
  CSimpleXmlWriter();
  ~CSimpleXmlWriter();

  void Open(const wstr& path, const str& rootTag);
  void Write(const str& tag, const str& value);
  void Close();

protected:
  std::ofstream m_out;
  str m_rootTag;
};

書ける XML は 1 つのルートタグからなるやつで、
Write で直属の子ノードを書けるだけです。

Open でルートノードの開始タグを書いて、
Close で終了タグを書けば OK です。

デストラクターでも、一応、Close() を呼びだすので、
終了タグを 2 回書き込まないように、m_out.is_open()
のときに終了タグを書いて、m_out.close() します。

ま、なんとなく実装できるでしょ。

読み込みの方も似たようなインタフェースを用意し、
Open でファイルをメモリーに全部読み込んじゃいます。

で、Read (Write の逆のやつ) では開始タグと終了タグを検索して
その間の値を、value に設定します。

難しくはないわな。

ご意見・ご要望連絡窓口


2017年08月15日(火)

win32、php で、base64 エンコード、デコードするには

今日も、こつこつコーディングしてたのですが、
特に、書くことも無いので、API の情報でも。

win32 API で、base64 エンコードするには、
CryptBinaryToString
base64 デコードするには、
CryptStringToBinary
を使います。

フラグには、CRYPT_STRING_BASE64 を指定すれば OK です。

ToString の方では、改行コードが挿入されますが、
CRYPT_STRING_NOCRLF も指定すると無しにできそうです。
(今、発見したので、試してない。やってみよっ)

一方、php で、base64 エンコードするには、
base64_encode
base64 デコードするには、
base64_decode
を使います。

ご意見・ご要望連絡窓口


2017年08月14日(月)

c++、http / https で php に接続 (その2)

c++ で暗号化したデーター (RSA) を php に送信し、
php でデコードするテストコードができました。

予想通りとはいえ、結構、時間かかったな〜。

HttpSendRequest を非同期で呼びだした場合、
なぜか、ヒープを破壊することがあって、
その破壊が自分のコードが原因じゃないことを
ある程度、確信するのに時間がかかりました。

そんなわけで、HttpSendRequest の挙動はかなり怪しいので
HttpSendRequestEx を使った方がいいよーな気がします。

もう一つは、x-www-form-urlencoded 形式で
フォームデーターを送った場合に、+ がスペースに
化けてたりすることに気づくのに少し手間取りました。

なんとなく、気持ち的に base64 エンコードしてるんだから
普通に送れるだろうと思いこんでいたのですが、
base64 エンコードに使用される記号 +、/、= は
3 つとも、URL には使用できない文字でした!

・・・

全然、だめじゃん^^

ご意見・ご要望連絡窓口


2017年08月08日(火)

http / https で php に接続

今日は、c++ コードから、http / https で
php に接続するテストコードを作成しました。

WinInet というライブラリーを使えばいいのですが、
真面目にやると、結構なコード量になります。

http / https の切り替え個所は 2 つ。

1 つ目は、InternetConnect で接続するポートを
INTERNET_DEFAULT_HTTP_PORT (http の場合)
INTERNET_DEFAULT_HTTPS_PORT (https の場合) にする。

2 つ目は、HttpOpenRequest のフラグに、
https の場合は、INTERNET_FLAG_SECURE を加える。

です。後は共通のコードで OK みたいですね。

で、フォームデーターをポストする部分ですが、ヘッダーで
Content-Type: application/x-www-form-urlencoded
を指定して、それっぽいデーターを送れば OK です。

現在のテストコードでは、
HttpAddRequestHeaders で、ヘッダーを指定してから
HttpSendRequest で、ポストデーターを書き込みでうまくいってます。

SendRequest にもヘッダーを指定する引数が
あるので、そこで指定してもよさそうです。

ところが、HttpSendRequest のかわりに、
HttpSendRequestEx してから、
InternetWriteFile でポストデーターを
書き込む方法がうまくいきません。

まぁ、うまくいく方法を使えばいいんですけど、
なんか釈然としないなー。

・・・

もちっと調べてみるかな。

・・・

追記
----
で、調べてみたら原因がわかりました。

php の方で、var_dump(getallheaders()); して
違いを見てみると、HttpSendRequestEx の方では、
Content-Length が 0 になってたので、
Write する予定のデーターサイズをヘッダーに加えると
あっさり、うまくいきました。

なるほどね。

ご意見・ご要望連絡窓口


2017年08月07日(月)

c++、RSA の鍵を XML 形式で出力するには?

今日は、c++ で RSA の鍵ペアーを
XML 形式で出力する方法を調べました。

c# だと、 RSACryptoServiceProvider::ToXmlString
で生成できるやつです。

結論からいうと、できました。

が、ずばりの関数とかは無さそうなので
自分でフォーマットする必要があります。

ちなみに、c# < - > c++ 間で
鍵を交換するだけなら、BLOB 形式ってのを
使うと、簡単にできます。

c# では、
RSACryptoServiceProvider::ExportCspBlob
RSACryptoServiceProvider::ImportCspBlob

c++ では、
CryptImportKey
CryptExportKey
を使います。

で、本題の XML 形式での出力方法ですが、
この BLOB 形式がほぼ XML 形式での表現
と一対一で対応する値を持つので、
フォーマットして出力すれば OK です。

結構なコード量になったりしますが、
必要な方のためにヒントだけ書いときますね。

値は、base64 エンコードして出力しますが
XML での出力はビッグエンディアン形式なので、
エンコード前に数値のバイトオーダーを逆転します。

Exponent の数値は、DWORD (4 バイト) ですが、
3 バイトで納まる数値が使われているため、.NET では、
3 バイトの数値を、base64 エンコード出力してるみたいです。

別に、4 バイトのままエンコードしても
読み取ってくれそうですが .NET の出力に合わせるには、
不要な上位バイトを削る必要があるようです。

以上。

あ、BLOB の内部形式はココ にありますよ。

ご意見・ご要望連絡窓口


2017年03月21日(火)

GetGlyphOutline で取得できる GLYPHMETRICS の性質について、調査終了

前の記事 の続きです。

私のパソコンにインストールされている全てのフォントの
全ての文字について GetGlyphOutline する実験が終了しました。

やはり、得られるグリフを - gmptGlyphOrigin.x + 1
平行移動すると、図形の描かれる x 座標を 0 以上にできました。

もちろん、未知のフォントでそうならない可能性もありますが、
gmptGlyphOrigin.x の定義からいって、そうならないとしたら、
フォントか OS の不具合と考えてよさそうです。

次に、- gmptGlyphOrigin.x + 1 平行移動したグリフの x 座標が、
常に、gm.gmBlackBoxX + 2 以下になるかのテストもしました。

これについてはならないフォントが見つかりましたが、
やはり、gm.gmBlackBoxX の定義からいって、
OS か フォントの不具合と考えてもよさそうです。

で、そうならないフォントは、@Malgun Gothic、
ハングル文字用のフォントみたいですね。(@ なので縦書き用)

うまくいかない文字は、U+302E、U+303E。
それぞれ、文字コード表によると、
Hangul Single Dot Tone Mark、
Hangul Double Dot Tone Mark。

このページ にある、去声、上声 記号だと思われます。

ま、縦書き用のフォントだし、
現在ではあんまり使われない記号っぽいですね。

ちなみに、この実験は、 文字に縁取りするノ の改良のために行いました。

文字に縁取りするノは文字や文章を画像に一括変換するソフト
です。 ホームページとかで気軽にカラフルな文字を
使ってみたい人は、是非、お試しあれ♪#

最新版は、こちらのページからダウンロードできます

で、この実験結果を受けて、文字に縁取りするノを
ちょっとだけ高速化する予定です。お楽しみに〜。

文字に縁取りするノ
文字に縁取りするノ - ダウンロード
文字に縁取りするノ - 更新履歴
ご意見・ご要望連絡窓口


| 1/4PAGES | >>