Win32/64技術 004 文字列グローバル変数にHGLOBALを使う一例

提供:yonewiki

Win32/64_アプリケーション開発に戻る。

前の記事:Win32/64技術 003 ワイド文字列→マルチバイト文字列変換

次の記事:[[Win32/64技術 005]]

概要

 グローバル変数の文字列変数を扱う手法についての記事です。文字列を格納するにはそれなりに容量が必要になってきます。使わない領域になるかもしれない文字列のためにゆとりをもってグローバル変数としてメモリを確保をするのは気が引けるものです。必要な時に必要なだけの文字数の領域を確保するようにしましょう。

 グローバル変数専用のヘッダファイルを作りましょう。利用用途をカテゴリごとに分類しておくと名前の重複が少なくなったりします。ここでは「global.h」とします。どのプログラムファイルからも参照できる変数として使うためにはヘッダファイル化しておくのが大事になります。例えばHGLOBAL型のHGLOBALstringという変数名をグローバル変数にするには以下のように設定します。

File:global.h

#pragma once
#ifndef __GLOBAL__
#define __GLOBAL__

//宣言する型名についての情報が含まれるヘッダファイルの読み込みは必要。
#include <Windows.h>

extern HGLOBAL HGLOBALwstring;;
extern HGLOBAL HGLOBALstring;;

#endif


 グローバル変数として定義しますが、ヘッダファイル内では、externキーワードを付けたものを宣言します。これは、関数でいうところのプロトタイプ宣言みたいなものになります。実体はここにありません。実体は各プログラムファイルの中のどこかで一度だけ宣言するとよいことになります。例えばmain.cppでは以下のように記述します。


file:main.cpp

#include <Windows.h>
#include "global.h"

HGLOBAL HGLOBALwstring;
HGLOBAL HGLOBALstring;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreInst, LPSTR lpszCmdLine, int nCmdShow){
    wchar_t pwchString[] = L"グローバル変数に格納される文字列データ";
    char pchString[] = "This is global value.";

    size_t length = wcslen(pwchString);//19文字
    size_t length = strlen(pchString);//21文字

    HGLOBALwstring = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, (length + 1) * sizeof(wchar_t));
    HGLOBALstring = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, (length + 1));

    //使い始め
    wchar_t* pwchGlobalString = (wchar_t*)GlobalLock(HGLOBALwstring);
    char* pchGlobalString = (char*)GlobalLock(HGLOBALstring);



    //使い終わったら
    GlobalUnlock(HGLOBALwstring);
    GlobalUnlock(HGLOBALstring);

}


 と、上記のように使います。HGLOBALwstring = GlobalReAlloc(HGLOBALwstring, (length + 1) * sizeof(wchar_t), GMEM_MOVEABLE);みたいに、文字列を拡張していく処理も実施できます。その後またpwchGlobalString = (wchar_t*)GlobalLock(HGLOBALwstring);にして、結び付ける処理も必要ですし、拡張したあとに文字列をつぎ足す処理をするのにstrcat_s(pwchGlobalString, length + 1, pwchAddString);のようにする必要があります。こういった処理は繰り返すので、独自に文字列操作関数を作ってしまった方が更に楽です。例えば、リテラル文字列をGlobal変数に格納する関数として、以下のようなものが作れるでしょう。


File:GlobalStringFunc.h

#pragma once
#ifndef __GLOBALSTRING__
#define __GLOBALSTRING__

#include <Windows.h>
#include "global.h"

bool AllocateGlobalMemoryW(wchar_t* str, HGLOBAL& HGLOBALdata);
void FreeGlobalMemory(HGLOBAL& HGLOBALdata);

#endif


File:GlobalStringFunc.cpp

#include <Windows.h>
#include "GlobalStringFunc.h"
#include "global.h"


bool AllocateGlobalMemoryW(wchar_t* str, HGLOBAL& HGLOBALdata) {
    // すでにメモリが確保されている場合、解放
    if (HGLOBALdata != nullptr) {
        GlobalUnlock(HGLOBALdata);
        GlobalFree(HGLOBALdata);
        HGLOBALdata = nullptr;
    }

    size_t length = wcslen(str);
    HGLOBALdata = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, (length + 1) * sizeof(wchar_t));

    if (HGLOBALdata == nullptr) {
        return false;
    }

    wchar_t* newstr = (wchar_t*)GlobalLock(HGLOBALdata);
    if (newstr != nullptr) {
        wcscpy_s(newstr, length + 1, str);
        GlobalUnlock(HGLOBALdata);
        return true;
    }
    else {
        GlobalFree(HGLOBALdata);
        HGLOBALdata = nullptr;
        return false;
    }
}

// グローバルメモリを解放する関数
void FreeGlobalMemory(HGLOBAL& HGLOBALdata) {
    if (HGLOBALdata != nullptr) {
        GlobalFree(HGLOBALdata);
        HGLOBALdata = nullptr;
    }
}


 何度も同じ処理をしている部分があると感じたものをこのように関数化していけるとよいでしょう。文字列操作の流派はいろいろあるので、自分からの提案はこのくらいにしておきます。


 以下のようにして使います。

HGLOBAL g_HGLOBALstring;

int WINAPI WinMain(HINSTANCE HINSTANCEinst, HINSTANCE HINSTANCEpreinst, LPSTR LPSTRcmdLine, int iCmdShow){
       
    wchar_t* pwchString;
    AllocateGlobalMemoryW(L"Hello World! こんにちは!世界。", g_HGLOBALstring);
    //使い始め
    pwchString = (wchar_t*)GlobalLock(g_HGLOBALstring);
    
    //使い終わったら
    GlobalUnlock(g_HGLOBALstring);
}

 

前の記事:Win32/64技術 003 ワイド文字列→マルチバイト文字列変換

次の記事:[[Win32/64技術 005]]

Win32/64_アプリケーション開発に戻る。