イネマルのプログラミング備忘録

趣味プログラマーのメモ

C / C++ の共用体(union)を初歩的に使う

入門時にイマイチ使いどころがわからんかった共用体

プログラミングを初めて超初期のころ入門書で出会った
”union” ”共用体” のキーワード
自分の使っていた入門書では
構造体の直後位に解説されていて
いったいどこで使うの?
といった感じで放置していたが
最近使う機会があったので、一応覚書

(自分なりの)結論

キャストとかを駆使せずに”データにアクセスする手段”
記述法だけ似ている構造体とは別物と考えて良し

目的

構造体にオペレーターやキャストを使用せずに配列のようにアクセスする

確認用のプログラム

Vector3型風の構造体pos{ x y z } の各要素に”[ ]”でアクセスする。
本来ならposは配列でないので”[ ]”でアクセスできないが
共用体の機能でアクセスを可能にする
※動作確認は、VC2013

#include	<iostream>
#include	<array>

int main()
{
	using namespace std;

	union testUnion{
		struct { float x, y, z; } pos;
		array<float, 3> v;	// 純粋なCなら float v[3];
	};
	testUnion uni;

	uni.v[0] = 100.0f;		// uni.pos.x = 100; と同じ
	uni.v[1] = 200.1f;		// uni.pos.y = 100; と同じ
	uni.v[2] = 300.2f;		// uni.pos.z = 100; と同じ

	// つまりこう書ける
	for (int id = 0; id < 3; ++id){
		uni.v[id] += 0.5f;
	}

	// 値表示
	cout << uni.pos.x << endl;
	cout << uni.pos.y << endl;
	cout << uni.pos.z << endl;

	// 入力待ち
	rewind(stdin), getchar();
	return 0;
}

あとがき

記事にするほどのネタでもないけど入門時の自分が見たら
少しくらいは助かる気がしたので備忘録行き

C# + DXライブラリ でIMEが動作しなくなる現象の回避方法

f:id:inemaru:20151125141302p:plain

C#+DXライブラリで IMEが無効化されてしまう現象

C#のWindowsFormApplicationとDXライブラリのC#用dllを使い
フォーム上でテキスト入力ができるコントロールを使うと
”ImeModeをOnにしてもIMEが無効化されてしまう”
現象にハマり・・・
とりあえず解決方法だけわかったので備忘録行き。

結論

”MakeKeyInput関数を呼ぶ!”

確認用のプログラム

注意点としては、DxLib_Init関数よりも後にMakeKeyInput関数を呼ばないと効果がないという点です。

※動作確認は、VS2013で行いました

namespace CSFormApp
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
            this.StartPosition = FormStartPosition.Manual;
            this.Location = new Point();
            this.StartPosition = FormStartPosition.CenterScreen;
            DX.SetOutApplicationLogValidFlag(0);
            DX.SetUserWindow(this.Handle);
            DX.DxLib_Init();
            // IMEを有効にする為の裏技
            DX.MakeKeyInput(0, 0, 0, 0);
        }
    }
}

あとがき

DXライブラリ内で呼ばれるAPIの関係で
こういった現象が起こっていると思われます。(たぶん)

とにかく
DX.DxLib_Init();より後にMakeKeyInput関数をを呼べばIMEが有効になるので、

とりあえず使えるようにするのであれば、
DX.MakeKeyInput(0, 0, 0, 0);
コンストラクタやフォームロード時に呼べば解決します。

C++でワイド文字(wchar_t)を使うときの注意点 ~ロケールを添えて~

f:id:inemaru:20150923003606p:plain

wchar_tを使う!

c++で文字を扱うときに、char型とwchar_t型があります。
char型と同じ感覚で使うと、要らないところでハマります。
自分がハマったので備忘録行き。

先に、結論だけ書くと
”wchar_tを使うならロケール設定をしよう!”
という事です。

確認用のプログラム

C++で現在のロケールを取得しながら
処理を目で追ってみました。

ロケールを取得した段階で "C" が返ってきたら危険。
即座に、設定するべきでしょう。

※動作確認は、VC2010とVC2013で行いました

#include <iostream>	// 標準入出力
#include <locale>	// ロケール関連
#include <clocale>	// Cのロケール関連
#include <string>	// stdの文字列クラス

using namespace std;

int main(){
	// 適当な文字列変数
	string	str("char");
	wstring	wstr(L"wchar_t");

	// ロケールを表示する関数
	auto DispLocale = [](){
		string locstr = std::locale().c_str();
		if(locstr == "C"){
			locstr += "(初期値です)";
		}
		cout << "現在のロケールは、" << locstr << endl << endl;
	};

	// 現在のロケール設定を表示
	DispLocale();

	// char文字の出力
	cout << str  << " char(string)は特に設定なしで表示できる" << endl << endl;

	// wchar_t文字の出力
	cout << "ロケールの設定なしでwcoutすると強制的にwcoutの処理が打ち切られる?" << endl << endl;
	// wcout << wstr2 + L"日本語は表示されない" << endl;
	
	// ロケールの設定
	cout << "ロケールの設定を変更します" << endl << endl;
	locale::global(locale(""));	// ""で処理系のシステムのデフォルトになるそうです
	// もしくは、
	//locale::global(locale("japanese"));
	// かつ、WindowsAPIを使うなら
	//setlocale(LC_ALL,"japanese");

	// 変更されたロケール設定を表示
	DispLocale();

	// wchar_t(wstring)は設定すると表示できる
	wcout << wstr + L" 日本語が表示される!" << endl << endl;
	
	rewind(stdin), getchar();	// キー入力で終了

	return 0;
}

あとがき

以下のリンクがすごく参考になりました。
Windows API on C++

単純にwchar_tで日本語が使いたいのであれば
std::locale::global(std::locale(""));
の一行で一応動いているようです。

ただし、WindowsAPIを使用するなら
std::locale::global(std::locale("japanese"));
std::setlocale(LC_ALL,"japanese");
とするべきでしょう。

Visual Studio 2010 C++ リファクタリング

f:id:inemaru:20150912215136p:plain
【目的】
今更だけど Visual Studio 2010 C++リファクタリング(自動リネーム)を使う

【達成条件】
・無料でやる

【注意】
・正攻法ではありません(故に↓)
・すべて個人の責任で行ってください(こちらは一切の責任を持ちません)
・VS2013(以降)は、公式で配布があるので無用の産物。

【環境】
・動作環境
  Windows 8.1 Pro
・開発環境
  Microsoft Visual Studio 2010 Professional

【方法】
1: Refactor!C++をダウンロード
2: RefactorCPP-11.2.7.exeをインストール
3: インストール完了後にシャットダウン(※この時、絶対にVSを起動しないこと)
4: CodeRushXpressをダウンロード
5: インストール完了後にシャットダウン(※この時、絶対にVSを起動しないこと)
6: PCを起動したらVSを起動し、エラーが出なければ成功!


【ちなみに】
・途中の工程で、もしVSを起動すると・・・
初回起動のみ正常に動作(してるように見える)、
2回目以降の起動で、ものすごい勢いでメモリを消費して
下手するとPCごと落ちます。

・ちなみに失敗したときのエラーはこんなの
devenv.exe Assert Failure
Expression: [mscorlib recursive resource lookup bug]
Description: Infinite recursion during resource lookup within mscorlib. This may be a bug in mscorlib, or potentially in certain extensiblity
points such as assembly resolve events or CultureInfo names. Resource name: Word_At

エラーの正体・・・拡張機能で使用されている実行ファイルのバグ

【あとがき】
約1年前に、身内で話題になり、結構頑張って調べた後
一過性の話題のまま忘れ去られようとされていた情報
データの整理中に当時自分が作った、インストールのメモが出てきたので備忘録行き決定
それが、今更VS2010のネタを書くに至った理由

DXライブラリでフォントファイルからフォント名を取得して使う

f:id:inemaru:20150628061548p:plain 
【追記】

2017/06/11
ttf, otf 限定で、この記事より高速にフォント名を取得する方法について書きました。
inemaru.hatenablog.com















以下の記事は、GDI+を使用したバグ持ちコードを含むので、
GDI+のPrivateFontCollectionについて知りたい場合以外
需要ないです。(なので、読まなくて良いです。)

【目的】
DXライブラリでインストールされていないフォントを簡単に使う
書体名またはデータ名(*.ttf | *.otf | *.ttc)で使えるようにする


【準備】
動作確認した環境
・動作環境
  Windows 8.1 Pro
・開発環境
  Microsoft Visual Studio 2010 Professional
  DXライブラリ VisualC++用(Ver3.14d)

使用させてもらったもの
・DXライブラリ
 http://homepage2.nifty.com/natupaji/DxLib/
・しねきゃぷしょん
 http://chiphead.jp/
・ペン字版 Y.OzFont TTCパック
 http://yozvox.web.fc2.com/82A882B782B782DF8374834883938367.html

作った物
・ PrivateFontManager
PrivateFontManager.zip(PrivateFontManager.zip) ダウンロード | イネマルの備忘倉庫 | uploader.jp
 GDI+のPrivateFontCollectionを使ってフォント名を取得し、
 インストールしていないフォントを使用可能な状態にしてくれるクラス
 (自動解放機能付き)


【方法】
GDI+でフォント名を取得してそれをプログラム中で使用できるように
管理してくれるクラスを作成
デストラクタで自動解放するようにしてあるので
解放処理を、呼ぶ必要はなし

上記の PrivateFontManager をダウンロードして
プロジェクトに追加した状態で動きます

サンプルコード

#include "DxLib.h"
#include "PrivateFontManager.h"

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
    LPSTR lpCmdLine, int nCmdShow )
{
    // 開発環境のチェック
    static_assert( _MSC_VER >= 1600 , "VC2010(VC10.0)以降のコンパイラが必要です" ) ;

    // DXライブラリの準備
    ChangeWindowMode( TRUE ) ;  // ウィンドウモードで表示
    if( DxLib_Init() == -1 )    // DXライブラリ初期化処理
    {
            return -1;      // エラーが起きたら直ちに終了
    }

    // 見やすくする設定
    ChangeFontType( DX_FONTTYPE_ANTIALIASING_EDGE_8X8 ) ;
    SetFontSize( 36 ) ;

    // 白色の値を取得
    int Cr = GetColor( 255 , 255 , 255 ) ;

    // フォント管理クラスでフォントを使えるようにする
    PrivateFontManager lfm;
    auto ttfh = lfm.InstallPrivateFont( _T("cinecaption2.28.ttf") ) ;
    auto ttch = lfm.InstallPrivateFont( _T("YOzRA.TTC") ) ;

    // フォントのインストールに失敗していたら終了する
    if( ttfh == -1 || ttch == -1  )
    {
        OutputDebugString( _T("フォントのインストールに失敗しました") ) ;
        return 0 ;
    }
    
    // 文字列の描画
    DrawString( 10 ,  30 , _T("   ||| フォントファイルを |||") , Cr ) ;
    DrawString( 10 ,  90 , _T("   ||| DXライブラリで使う |||") , Cr ) ;
    DrawString( 10 , 150 , _T("デフォルトフォント") , Cr ) ;
    ChangeFont( lfm.GetFontNameFromList( ttfh ) , DX_CHARSET_DEFAULT ) ;
    DrawFormatString( 10 , 210 , Cr , _T("%s") , lfm.GetFontNameFromList( ttfh ) ) ;
    DrawFormatString( 10 , 270 , Cr , _T("TTCのフォント数 = %d") , lfm.GetFontListCount( ttch ) ) ;
    ChangeFont( lfm.GetFontNameFromList( ttch , 0 ) , DX_CHARSET_DEFAULT ) ;
    DrawFormatString( 10 , 330 , Cr , _T("%s") , lfm.GetFontNameFromList( ttch , 0 ) ) ;
    ChangeFont( lfm.GetFontNameFromList( ttch , 1 ) , DX_CHARSET_DEFAULT ) ;
    DrawFormatString( 10 , 390 , Cr , _T("%s") , lfm.GetFontNameFromList( ttch , 1 ) ) ;

    WaitKey() ;     // キーの入力待ち(『WaitKey』を使用)

    DxLib_End() ;   // DXライブラリ使用の終了処理

    return 0 ;      // ソフトの終了
}

【短所】
ちょっと、重い
でも、初期化時に呼ばれることを想定してるので許容範囲

環境によっては、動かない場合があるらしいです。
もしかしたら、ロケール回りかも?
原因が分かったら修正するつもりです。

【あとがき】
もちろん、ChangeFontとかCreateFontToHandleでも使えます
フォント名を取得するのにGDI+を使ったのは、複数の形式に対応する為ですが
ttf形式に固定するなら、もっと高速に処理を書けるかもしれません

【参考】
・DXライブラリ置き場
http://homepage2.nifty.com/natupaji/DxLib/
・DXライブラリで任意のフォントを使用する
http://d.hatena.ne.jp/willowlet/20091231/1262231680
・DXライブラリのフォントハンドル
http://dixq.net/g/04_03.html
・GDIのプライベートフォントコレクションについて(英語)
https://msdn.microsoft.com/en-us/library/windows/desktop/ms533820(v=vs.85).aspx

ブログはじめました。

はじめまして、こんにちは。

 

技術的なことを中心に、

備忘録的な感じで更新して行きたいと思ってます。

 

がんばるぞ!