- はじめに
- C++のビルド環境について
- Dllプロジェクトの作成
- C++で関数を実装する
- GameMakerプロジェクトにDllファイルをインクルードする
- GMLからC++の関数を呼び出す
- 実践
- まとめ
はじめに
この前、初めてC++でGameMakerStudio2の拡張機能を作りました。
その時なんですが、実は拡張機能の作り方がちょっと難しくて苦戦しちゃいました。(ジョウホウガスクナイ)
そこで、自分の備忘録として今回はC++での拡張機能(.dll)の作り方についてまとめようと思います。
C++のビルド環境について
今回の記事では、C++のビルド環境にVisualStudioを用いようと思います。
無料で使えて高性能ですので、まだC++のビルド環境が無かったら、VisualStudioを使用することをオススメします。
既にC++のビルド環境が存在するのであれば、この項目はスキップしてOKです。
VisualStudio2022のインストール
現在(2025/08/14)で最新版のVisualStudio2022をインストールします。
下記サイトにアクセスして、VisualStudio2022 Communityのインストーラーをダウンロードします。

ダウンロードされたインストーラーをダブルクリックします。

インストール前にこのような画面が出てきたら「続行」を選択してください。

そしたら下記のような、インストールする項目を選ぶ画面が出てきます。

今回は .dllファイルのビルドさえ出来ればよいので、
「デスクトップとモバイル」の中にある「C++によるデスクトップ開発」にチェックを入れます。

そしたら、右下のインストールをクリックします。

インストール完了までは時間かかりますが、待ちましょう...。

下記のようなウィンドウが表示されたらインストール完了です。OKを押しましょう。

もし仮に、さらにVisualStudioで使いたいテンプレートがあっても後からインストールできるので安心してください。
Dllプロジェクトの作成
では次は、VisualStudioでDllをビルドできるプロジェクトを作成しましょう。
Windows検索画面から「Visual Studio 2022」と検索して、ソフトを起動します。

初回の起動の場合、Microsoftアカウントのサインインなどの手続きがあります。
手順に従ってサインインしてください。
サインイン後、プロジェクト起動画面になります。
新しいプロジェクトの作成を選択してください。

次はテンプレート選択画面になるため、
「ダイナミック リンク ライブラリ(DLL)」を選択して「次へ」を選択します。

このような画面が表示されればプロジェクトの作成に成功しています。

C++で関数を実装する
さて、ここからが本番ですね。
C++で関数を実装していきましょう。
GML関数公開用ファイル作成
GMLに公開する関数をまとめるファイルを作ります。
右の「ソリューションエクスプローラー」から「ヘッダーファイル」と書かれたパッケージを選択肢、
右クリックをします。

右クリックするとメニューが出てくるので、「追加」->「新しい項目」を選択します。

すると作成コンパクトビューが表示されるので、「すべてのテンプレートを表示」をクリックします。

次はテンプレート選択画面が表示されるので
- テンプレートから「ヘッダーファイル」を選択
- ファイル名は「GmlExportedFunction.h」に指定
- 右下の「追加」をクリック
してください。

ヘッダーファイル内に「GmlExportedFunction.h」ファイルが作成されていればOKです。

C++では、このように作成したヘッダーファイル(.h)に関数の宣言を書いていきます。
ヘッダーファイルに関数を宣言する
次は先ほど作成したヘッダーファイルに関数を宣言します。
「ソリューションエクスプローラー」から「GmlExportedFunction.h」をダブルクリックして開きます。

公開用のマクロ宣言
GMLに関数を公開するには、関数を定義する前に
「extern "C" __declspec(dllexport)」と記述する必要があります。
とは言えこれを毎回書くのはめんどくさいので、
冒頭に関数公開用のマクロを定義して簡略化します。
// GameMakerStudio2向けにDLLを作る際、 // 関数をGMLから呼び出せるようにするためのエクスポートマクロ。 // extern "C" : C言語形式でエクスポートし、名前修飾を防ぐ // __declspec(dllexport) : この関数をDLL外部に公開する(Windows専用) #define GMS2EXPORT extern "C" __declspec(dllexport)
GML側に公開する関数を宣言する際は、このマクロを用います。
// 例 GMS2EXPORT void Function();
使用できる型
GMLに公開する関数の戻り値と引数には「double」型と「char*」型しか指定できません。
GMS2EXPORT double AddValue(double a, double b);
double型は数値を受け取る or 返す時に使います。
整数、小数どちらも使用することが出来ます。
GameMakerでいう「Real」型と同じ扱いが出来ます。
GMS2EXPORT const char* ChangeText(const char* text);
char*型は文字列を受け取る or 返す時に使います。
GameMakerでいう「String」型と同じ扱いが出来ます。
charではなくchar*なので注意してください。
※「*」を付けないと正しく文字列を受け取れません。
▶なんで「*」を付ける必要があるのか?
C++に慣れていない方にはなかなか見慣れない書き方だと思います。
実は変数に「*」を付けるか付けないか変数の扱い方が変わります。
charは1バイト分の値しか保持できません。文字で言えば1文字分です。
そのため、文字列全体を扱うことはできません。
char*は「char型のデータが並んでいる場所の先頭アドレス」を保持します(所謂、ポインタ)。
文字列は複数の文字が連続して並んでおり、その先頭位置さえわかれば、
後ろの文字も順番に読み取ることができます。
* をつけることで、char型のポインタを保持できるようになるわけです。
なので、今回は * が付いているわけですね。
とは言えC++に慣れていないとよくわからないと思うので、
GMLの「String」はC++だと「char*」で、
「char」は1バイトしか値が入らないものだ、と覚えておけばOKです。
サンプル関数を宣言
では、上記を踏まえていくつか関数を定義してみます。
先程のファイルに対して下記を記述してください。
/// <summary> /// 複数の double 値を受け取り、その合計を返す関数 /// </summary> /// <param name="a">1つ目の数値</param> /// <param name="b">2つ目の数値</param> /// <param name="c">3つ目の数値</param> /// <returns>引数の合計</returns> GMS2EXPORT double AddThreeNumbers(double a, double b, double c); /// <summary> /// 文字列を受け取り、"Hello, " を先頭につけて返す関数 /// </summary> /// <param name="text">文字列</param> /// <returns>"Hello, " + text の文字列</returns> GMS2EXPORT const char* SayHello(const char* text);
こんな感じで宣言すればGMLから呼び出すことが出来ます。
ソースファイルに関数を実装する
次はソースファイル(cpp)に関数の中身を実装します。
C++ではヘッダーファイル(.h)に関数を定義し、ソースファイル(.cpp)に中身の処理を実装します。
ソースファイルを作成するため、「ソリューションエクスプローラー」から
「ソースファイル」フォルダを選択して右クリックをし、新しい項目の追加を行います。

テンプレート作成画面では「C++ファイル(cpp)」を選択し、
ファイル名を「GmlExportedFunction.cpp」に変更して「追加」をクリックしてください。

このような画面になればOKです!

コード実装
ソースファイルを作成できたので、先程作った関数の中身を実装していきます。
先ほどヘッダーファイルで定義した2つの関数を実装したコードが下記です。
#include "pch.h" #include "GmlExportedFunction.h" #include <string> double AddThreeNumbers(double a, double b, double c) { return a + b + c; } const char* SayHello(const char* text) { // GMLから呼び出す場合、返すポインタは関数終了後も有効である必要があるため、 // 静的な std::string に文字列を保持し、その内部バッファへのポインタを返す。 static std::string result; result = "Hello, "; result += text; return result.c_str(); }
こちらをcppファイルに書き込んでください。
プロジェクトのビルド
次はビルドを行います。
デフォルトだとDebugビルドになっていると思うので、
それをReleaseビルドに変更します。
画面上の「Debug」と書かれた部分をクリックしてください。

それを「Release」に変更してください。

この状態で「Ctrl + B」もしくは、
上のメニューの「ビルド」をクリックして、出てきたメニューから「ソリューションのビルド」を選択してください。

ビルドが完了して、出力ウィンドウが下記のように表示されればビルド成功です!

GameMakerプロジェクトにDllファイルをインクルードする
次は、先程作ったdllファイルをGameMakerに追加します。
「ソリューションエクスプローラー」のプロジェクトを右クリックし、
「エクスプローラーで開く」を選択します。

そしたら開いたフォルダーから「x64」->「Release」と移動します。
すると、中に「プロジェクト名.dll」というファイルが存在するフォルダーに遷移します。

そしたら、このdllファイルをGameMakerのプロジェクトまでドラッグしましょう。

これで追加が完了です。
GMLからC++の関数を呼び出す
ついにここまできました。
最後に、GMLでC++の関数を呼び出すようにします。
といった手順です。
C++の関数をGMLで定義する
そのために、まずはオブジェクトを1つ作りましょう。
Createイベントを追加してください。

C++の関数をGMLで定義するには「external_define」関数を使います。
external_define
external_defineはDLLの関数を呼び出すための設定を行う関数です。
関数名、呼び出し規約、戻り値の型、引数の数と型を指定します。
// 構文 external_define(dll, name, calltype, restype, argnumb, argtype[0], argtype[1], ...);
| 引数名 | 型 | 説明 |
|---|---|---|
| dll | 文字列 | DLLファイル名(パス込み可) |
| name | 文字列 | DLL 内の関数名 |
| calltype | 定数 | 呼び出し規約(dll_cdecl または dll_stdcall) |
| restype | 定数 | 戻り値の型(ty_real または ty_string) |
| argnumb | 数値 | 引数の数(0〜15)※4つ以上はすべて ty_real |
| argtype[...] | 定数 | 各引数の型(ty_real または ty_string) |
・呼び出し規約とは
* dll_cdecl - C/C++標準の呼び出し規約(通常はこちらを使用)
* dll_stdcall - Windows API 標準の呼び出し規約(Windows専用)
・型について
* ty_real … 実数(double)
* ty_string … 文字列(char*)
この関数を使って定義します。
external_defineを使って関数の定義
では、先程C++で宣言した関数を定義してみましょう。
オブジェクトのCreateイベントに下記を記述してください。
// AddThreeNumbers 関数を DLL から読み込み // 引数: 実数3つ、戻り値: 実数 AddThreeNumbers = external_define( "GameMakerDll.dll", // DLLファイル名 "AddThreeNumbers", // DLL内の関数名 dll_cdecl, // 呼び出し規約(C/C++標準) ty_real, // 戻り値型(実数) 3, // 引数の数 ty_real, ty_real, ty_real // 各引数の型 ); // SayHello 関数を DLL から読み込み // 引数: 文字列1つ、戻り値: 文字列 SayHello = external_define( "GameMakerDll.dll", // DLLファイル名 "SayHello", // DLL内の関数名 dll_cdecl, // 呼び出し規約(C/C++標準) ty_string, // 戻り値型(文字列) 1, // 引数の数 ty_string // 引数の型 );
これでOKです!
GMLからC++の関数を呼び出す
次は、external_defineで定義した関数を呼び出します。
呼び出すにはexternal_call関数を使用します。
external_call
external_callは、external_define()で登録したDLLの関数を実際に呼び出すための関数です。
事前に登録した関数IDと、必要な引数を渡します。
//構文 external_call(id, args[0...15]);
| 引数名 | 型 | 説明 |
|---|---|---|
| id | External Function | external_define() で取得した関数ID |
| args[...] | 実数 または 文字列 | 関数に渡す引数(型は登録時の指定と一致させる) |
戻り値 登録時に指定した戻り値の型に応じて、実数(real)または文字列(string)が返ります。
この関数を使用することで、先ほどexternal_defineで定義した関数を呼び出せます。
external_callを使って関数を呼び出す
では実際にexternal_callを使って関数を呼び出してみましょう!
先ほどのオブジェクトのCreateイベントの続きに、下記を記述してください。
// DLL内の AddThreeNumbers 関数を実行(10 + 20 + 30) var _addThree = external_call(AddThreeNumbers, 10, 20, 30); // DLL内の SayHello 関数を実行("Hello, hogehoge" を返す想定) var _sayHello = external_call(SayHello, "hogehoge"); // 結果をデバッグ出力 show_debug_message($"AddThreeNumbers {_addThree}"); show_debug_message($"SayHello {_sayHello}");
これで呼び出しはOKです!
ロードしたdllファイルをアンロードする
最後に、ロードしたdllファイルをゲーム終了時にアンロードする方法です。
これを行わないとメモリが残り続ける可能性があるため注意が必要です。
アンロードするためにはexternal_free関数を使用します。
external_free
external_freeは、指定したDLLの使用を終了し、そのメモリを解放します。
ゲーム中でそのファイルが不要になった時に呼び出します。
// 構文 external_free(name);
| 引数名 | 型 | 説明 |
|---|---|---|
| name | 文字列 | 解放したい DLL または dylib の名前(パス込み可) |
これだけです。
external_freeを使ってDLLのアンロード
先ほど作ったオブジェクトにClean Upイベントを追加し、
そこに下記のコードを追加します。
// GameMakerDll.dll のメモリを解放 external_free("GameMakerDll.dll");
これで解放は完了です。
実践
では、先程作ったオブジェクトをルーム内に配置してログをチェックしてみましょう!
AddThreeNumbers 60 SayHello Hello, hogehoge
このようなログが表示されれば成功です!!
まとめ
今回はGameMakerStudio2でC++を使った拡張機能の作り方についてまとめました。
色々セットアップや組み方が特殊でなかなかわかりにくいんですよね。
今回はセットアップの部分から説明したので、ある程度わかりやすく書けたと思います!
これを経て、C++を使った拡張機能がもっと増えてくれたらなと思います。
今後はこの拡張機能でのC++での組み方について、Tipsなどまとめたいと思います。
特にsurfaceや構造体等のデータ渡しや、別ウィンドウの作成などまとめていく予定です。