○共有メモリを使ったアプリケーション間の通信
共有メモリを使用しますのでスピードがかなり速いです
複数のアプリケーションで文字列の同時通信ができます。
----イメージ図-----
VB6 + shard.dll ⇔ |------------------------|
VB.net + shard.dll ⇔ | システム内の共有メモリ |
VBA + shard.dll ⇔ | |
VC ⇔ |------------------------|
その他、DLLの読み出せる言語ならばアプリケーション間のshardが可能です。
読み書きできる文字数は、32768バイトです。
それ以上の文字数は決して書き込まないで下さい。
@ここからAppConversation2.ZIP (排他処理追加済み。VBAの対応済み)をダウンロードしてください。
もしくは、下の方にソースがありますのでコンパイルして作成してください。
Aそのファイルを解凍するとshard.dllが出てきます。作成中のアプリケーションの実行ファイルの横にコピーしてください。
複数のshard.dllコピーして使用したとしても、システム内の共有メモリは1つしか無いので、お互いのアプリケーションが通信できます。
■ VB6でのサンプル
Private Declare Sub SetString Lib "shard.dll" (ByVal str As String)
Private Declare Function GetString Lib "shard.dll" () As String
Private Sub Command1_Click()
Call SetString("書き込む文字列")'共有メモリに書き込み
End Sub
Private Sub Command2_Click()
Command2.Caption = GetString()'共有メモリから読み出し
End Sub
▼ VB6のアプリケーション内部の動作を調べるために利用する時には、DLLの場所が開発環境と実行ファイル形式により変わるのでDLLを特定の場所に置いて、パスを直接指定した方が便利です。
Private Declare Sub SetString Lib "c:\ shard.dll" (ByVal str As String)
Private Declare Function GetString Lib "c:\ shard.dll" () As String
また、OSのバージョンにより SetString でエラーが起きる(windows10だとエラーが起きた)のでエラー処理で囲まないとプログラムが落ちます。
On Error Resume Next
Call SetString("Private Sub Check1_Click(Index As Integer)") '共有メモリに書き込み
On Error GoTo 0
注意) SetString が開発環境では動作しますが、実行ファイルではプログラムが無言で落ちます←現在原因不明(Windows10で確認)
意味がわからないが、 Form_Load() の先頭で書き込む事により解決した。
Private Sub Form_Load()
On Error Resume Next
Call SetString("load") '共有メモリに書き込み
On Error GoTo 0
....
■ VB.netでのサンプル
<System.Runtime.InteropServices.DllImport("shard.dll")> _
Private Shared Sub SetString(ByVal str As String)
End Sub
<System.Runtime.InteropServices.DllImport("shard.dll")> _
Private Shared Function GetString() As String
End Function
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
SetString("書き込む文字列")'共有メモリに書き込み
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Debug.WriteLine(GetString())'共有メモリから読み出し
End Sub
■ Excel VBAでのサンプル
DLLの場所の指定がよくわからないので C ドライブ直下にコピーしてパスを直接指定しています。
SetString関数の呼び出しで書き込めるようだがエラーで常に停止するため On Error Resume Next で囲んであります。
また、文字列なしの状態で書き込むとエラーが発生します。
GetStringはVBAではまともに動作しません、島崎様指摘(ASCI文字からStringへの変換がうまく行かない為)
そのため、GetData関数を使用します、呼ぶたびに共有メモリの一文字づつの値を取得し文字の終端では0を受け取ります。
2バイト文字は対応できません(文字化け必須)、1バイト文字のみです。
CommandButton1_Click()にてTextBoxの文字列を共有メモリに書き込み、CommandButton2_Click()にて共有メモリの文字を読み出してメッセージボックスに表示するようになっています。
Option Explicit
Private Declare Sub SetString Lib "C:\shard.dll" (ByVal str As String)
Private Declare Function GetData Lib "C:\shard.dll" () As Byte
Private Sub CommandButton1_Click()
Dim str As String
str = TextBox1.Text
If str <> "" Then
On Error Resume Next
SetString (str)
On Error GoTo 0
End If
End Sub
Private Sub CommandButton2_Click()
Dim str As String
Dim pos As Byte
pos = GetData()
While 0 <> pos
str = str + CStr(Chr(pos))
pos = GetData()
Wend
MsgBox (str)
End Sub
▼ Excel VBAでのサンプル2
2025年8月 島崎様がすばらしいサンプルを作成してくださいました。
これにより、DLLの配置の問題と2バイト文字を受け取れない問題が解決されます。
内容をそのまま載せます
因みに以下のようにすると、2byte 文字も上手く受信できます。
また、EXCEL ファイルと同じ場所に shard.dll を置いて実行できます。
(フルパスで記述する必要がなくなります)
以上、ご参考まで。
Declare Function GetData Lib "shard.dll" () As Byte
Sub GetMeasurement()
Dim pos As Byte
Dim str As String
ChDrive Drive:=Left(ThisWorkbook.Path, 1)
ChDir Path:=ThisWorkbook.Path
str = ""
pos = GetData()
While (pos <> 0)
str = str & ChrB(pos)
pos = GetData()
Wend
MsgBox (StrConv(str, vbUnicode))
End Sub
■ shard.dllの中身
VC6 Win32 DLL にて作られています。
バグがあったら、連絡ください。
#include <stdio.h>
#include <windows.h>
HANDLE hFile;
char buff[32768]="";
extern "C" __declspec(dllexport) char* GetString(void){
//アドレスを取得
LPVOID hMap = MapViewOfFile( hFile, FILE_MAP_WRITE | FILE_MAP_READ, 0, 0, 0 ) ;
strcpy(buff,(char*)hMap);//読み出し
UnmapViewOfFile(hMap);
return buff;
}
extern "C" __declspec(dllexport) void SetString(char*str){
//アドレスを取得
LPVOID hMap = MapViewOfFile( hFile, FILE_MAP_WRITE | FILE_MAP_READ, 0, 0, 0 ) ;
strcpy((char *)hMap,str);//書き込み
UnmapViewOfFile(hMap);
}
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch(ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
hFile = CreateFileMapping( (HANDLE)0xFFFFFFFF, NULL, PAGE_READWRITE, 0, 32768, "AppConversation") ;
break;
case DLL_PROCESS_DETACH:
CloseHandle( hFile) ;//メモリマップドファイルをクローズ
break;
}
return TRUE;
}
▼ 排他処理の追加
実際に使用してみて、共有メモリに対して複数プロセスから読み書きすると、書き込み中に読みだしてしまったり、読み出し中に書き込んでしまったりと、
トラブルが発生すると思います。
そこで、排他処理を追加したのが次のコードです。
#include <stdio.h>
#include <windows.h>
HANDLE hFile,hMutex ;
char buff[32768]="";
extern "C" __declspec(dllexport) char* GetString(void){
HANDLE h=OpenMutex(MUTEX_ALL_ACCESS,FALSE,"MUTEX1");//排他制御開始
//アドレスを取得
LPVOID hMap = MapViewOfFile( hFile, FILE_MAP_WRITE | FILE_MAP_READ, 0, 0, 0 ) ;
strcpy(buff,(char*)hMap);//読み出し
UnmapViewOfFile(hMap);
ReleaseMutex(h);//排他制御終了
CloseHandle(h);
return buff;
}
extern "C" __declspec(dllexport) void SetString(char*str){
HANDLE h=OpenMutex(MUTEX_ALL_ACCESS,FALSE,"MUTEX1");//排他制御開始
//アドレスを取得
LPVOID hMap = MapViewOfFile( hFile, FILE_MAP_WRITE | FILE_MAP_READ, 0, 0, 0 ) ;
strcpy((char *)hMap,str);//書き込み
UnmapViewOfFile(hMap);
ReleaseMutex(h);//排他制御終了
CloseHandle(h);
}
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch(ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
hFile = CreateFileMapping( (HANDLE)0xFFFFFFFF, NULL, PAGE_READWRITE, 0, 32768, "AppConversation") ;
hMutex = CreateMutex(NULL,FALSE,"MUTEX1");//排他制御のMUTEXを作成
break;
case DLL_PROCESS_DETACH:
CloseHandle(hMutex);//排他制御のMUTEXを廃棄
CloseHandle( hFile) ;//メモリマップドファイルをクローズ
break;
}
return TRUE;
}
▼ VBAの対応
2025年8月 島崎様によると、EXCEL 2000 と 2002以外でのVBAでは動作しない可能性と連絡をうけました。
VBAでのGetString動作で渡される値がVBAのString文字列とは異なっており、正常に動作していませんでした。
DLLからVBAへの文字列渡しを試した見た所、配列の参照渡しはうまくいきませんでした。
引数を渡して、値を取得するのもうまく行きませんでした。
試行錯誤の結果、新旧Excelで唯一うまく行った方法はDLLから単一の数値を返す関数はきちんと動作する事でした。
これを応用して対応してみたいと思います。
#include <stdio.h>
#include <windows.h>
HANDLE hFile,hMutex;
char buff[32768]="";
extern "C" __declspec(dllexport) char* GetString(void){
HANDLE h=OpenMutex(MUTEX_ALL_ACCESS,FALSE,"MUTEX1");//排他制御開始
//アドレスを取得
LPVOID hMap = MapViewOfFile( hFile, FILE_MAP_WRITE | FILE_MAP_READ, 0, 0, 0 ) ;
strcpy(buff,(char*)hMap);//読み出し
UnmapViewOfFile(hMap);
ReleaseMutex(h);//排他制御終了
CloseHandle(h);
return buff;
}
//VBAの値取得関数
int i;
extern "C" __declspec(dllexport) unsigned char GetData(void){
if(0==i) GetString();
if(buff[i]){
return buff[i++];
}else{
i=0;
return (unsigned char)0;
}
}
extern "C" __declspec(dllexport) void SetString(char*str){
HANDLE h=OpenMutex(MUTEX_ALL_ACCESS,FALSE,"MUTEX1");//排他制御開始
//アドレスを取得
LPVOID hMap = MapViewOfFile( hFile, FILE_MAP_WRITE | FILE_MAP_READ, 0, 0, 0 ) ;
strcpy((char *)hMap,str);//書き込み
UnmapViewOfFile(hMap);
ReleaseMutex(h);//排他制御終了
CloseHandle(h);
//MessageBox(GetDesktopWindow(),str,"",0);
}
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch(ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
hFile = CreateFileMapping( (HANDLE)0xFFFFFFFF, NULL, PAGE_READWRITE, 0, 32768, "AppConversation") ;
hMutex = CreateMutex(NULL,FALSE,"MUTEX1");//排他制御のMUTEXを作成
break;
case DLL_PROCESS_DETACH:
CloseHandle(hMutex);//排他制御のMUTEXを廃棄
CloseHandle( hFile) ;//メモリマップドファイルをクローズ
break;
}
return TRUE;
}
赤文字部分が追加された関数です、呼ばれるたびに文字を一文字づつ返して終端では0を返します。
VBA側では0が来るまで繰り返しGetDataを呼び、一文字づつ文字に変換しStringに追記する仕組みです。
2バイト文字は対応できません(文字化け必須)、1バイト文字のみです。
■ C++言語での文字列のやり取り
難しい事を何も考えなくても VB6 ←→ VC6 での文字列のやり取りが出来るようです。
C++言語の場合にはDLLを使用しなくてもよいので、直接プログラムに書き込みます。
以下のコードがVB6とVC6での文字列のやり取りをしたプログラム
#include <stdio.h>
#include <windows.h>
HANDLE hFile,hMutex;
char buff[32768]="";
char* GetString(void){
HANDLE h=OpenMutex(MUTEX_ALL_ACCESS,FALSE,"MUTEX1");//排他制御開始
//アドレスを取得
LPVOID hMap = MapViewOfFile( hFile, FILE_MAP_WRITE | FILE_MAP_READ, 0, 0, 0 ) ;
strcpy(buff,(char*)hMap);//読み出し
UnmapViewOfFile(hMap);
ReleaseMutex(h);//排他制御終了
CloseHandle(h);
return buff;
}
void SetString(char*str){
HANDLE h=OpenMutex(MUTEX_ALL_ACCESS,FALSE,"MUTEX1");//排他制御開始
//アドレスを取得
LPVOID hMap = MapViewOfFile( hFile, FILE_MAP_WRITE | FILE_MAP_READ, 0, 0, 0 ) ;
strcpy((char *)hMap,str);//書き込み
UnmapViewOfFile(hMap);
ReleaseMutex(h);//排他制御終了
CloseHandle(h);
}
int main(){
hFile = CreateFileMapping( (HANDLE)0xFFFFFFFF, NULL, PAGE_READWRITE, 0, 32768, "AppConversation") ;
hMutex = CreateMutex(NULL,FALSE,"MUTEX1");//排他制御のMUTEXを作成
printf("%s\n",GetString());//共有メモリから読みだす
getchar();
SetString("あいうえおtest12345");//共有メモリに書き込む
getchar();
CloseHandle(hMutex);//排他制御のMUTEXを廃棄
CloseHandle( hFile) ;//メモリマップドファイルをクローズ
return 0;
}
▲トップページ
>
Visual BASIC と C#