
VC++でソフトを作成しています。
初心者なのでわからないことだらけです。
どなたかご教授お願いします。
■環境
Windows xp mode
Visual Studio 2010 Professional
VC++
フォームアプリケーション
.net Framework4.0
■相談内容
アプリ1のtextBoxに入力された文字列をアプリ2に送信して、アプリ2のtextBoxに表示させたいのですが、PostMessageを使用するとメッセージが送れません。
また、SendMessageを使用すると送れますが、共有メモリを使用すると文字列が途中で途切れてしまいます。
PostMessageと共有メモリの使用は指令なのではずせません。
理由は送信側のアプリがロックされるのを防ぐため、後に多数のアプリから送信した文字列を取得できるようにするためです。
下記にソースコードを記載しますので、どこが悪いのか、何が原因でそうなるのか、どうすれば正常に動作するようにできるのかを教えてください。
特に、ソースについてはどこをどのように直せば良いかを教えていただけるとありがたいです。
~送信側ソース~
#pragma once
#include<windows.h>
#include<iostream>
#include<fstream>
#include<string>
#include<msclr/marshal.h>
#pragma comment(lib,"user32.lib")
int s;
using namespace std;
using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;
using namespace System::Runtime::InteropServices;
using namespace msclr::interop;
[DllImport("user32.dll") ]
extern System::String^ FindWindow(String^ lpClassName, String^ lpWindowName);
[DllImport("user32.dll")]
extern System::String^ PostMessage(HWND hWnd, int Msg, int wParam, int lParam);
public: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e)
{
System::String^ moji_textBox4;
moji_textBox4=textBox4->Text;
s=textBox4->Text->Length+1;
COPYDATASTRUCT cd;
HWND hWnd;
char buffer[500];
sprintf_s(&buffer[0],5,"%s",moji_textBox4);
cd.dwData=0;
cd.cbData=s;//strlen(buffer)+1;
cd.lpData=buffer;
hWnd=::FindWindow(nullptr,L"アプリ2");
::PostMessage((HWND)hWnd,WM_COPYDATA,0,(LPARAM)&cd);
~受信側ソース~
#pragma once
#pragma comment(lib,"user32.lib")
#include<ctype.h>
#include<windows.h>
#include<msclr/marshal.h>
using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;
using namespace System::Runtime::InteropServices;
using namespace msclr::interop;
public: virtual void WndProc(System::Windows::Forms::Message% msg) override
{
if(msg.Msg== WM_COPYDATA)
{
COPYDATASTRUCT *cd;
cd=(COPYDATASTRUCT *)msg.LParam.ToInt32();
System::String^ str;
str=gcnew System::String((char *)cd->lpData);
pin_ptr<const wchar_t>pstr=PtrToStringChars(str);
System::String^ ShareMemoryName1=L"Information";
HANDLE hmap;
char *pmap;
marshal_context^ context= gcnew marshal_context;
LPCTSTR ShareMemoryName2 = context->marshal_as<LPCTSTR>(ShareMemoryName1);
hmap=::CreateFileMapping((HANDLE)0xFFFFFFFF,NULL,PAGE_READWRITE,0,2048,
(LPCTSTR)ShareMemoryName2);
pmap=(char *)::MapViewOfFile(hmap,FILE_MAP_ALL_ACCESS,0,0,1024);
System::String^ pstr1= gcnew System::String(pstr);
ZeroMemory(pmap,2048);
memcpy_s(pmap,2048,pstr,sizeof(pstr));
System::String^ str1;
str1= gcnew System::String((char *)pmap);
textBox6->Text=str1;
UnmapViewOfFile(pmap);
CloseHandle(hmap);
}
Form::WndProc(msg);
}
No.4ベストアンサー
- 回答日時:
共有メモリを使う場合には、送信側が書き込んだデータを受信側が読み込むよりも前に次のデータが送信側(複数ある場合は別の送信プログラムかもしれない)から書き込まれた場合に、データどのように格納しておくのか(上書きしていいのか、前のデータの末尾に追加するのか)を考える必要がありそうですね。
また、複数のプロセスからアクセスする共有メモリでは、排他制御を適切に行う必要があります。これは、もし
・送信側プログラムが共有メモリに書きこんでる真っ最中に、同時に受信側プログラムが共有メモリから読み込んだらどうなる?
・送信プログラムが複数になった場合、2つ(またはそれ以上)の送信プログラムが同時に共有メモリに書き込んだらどうなる?
ということを考えてみると、共有メモリに2つ以上のプログラムが同時にアクセスしてしまうことの問題が分かることでしょう。(いずれも受信データが壊れてしまう可能性がありますよね)
提示されたプログラムコードでは共有メモリを作成していますが、既存の部分でも排他制御を行っていないので、上記の問題がすでに存在していることになります。
排他制御をしないことによる不具合は読み書きのタイミングに依存して現れたり現れなかったりするので、問題が発見されるのがずっと後になることが多いです(そして不具合の再現性が低いので原因の特定も遅れてしまいます)。これから作る部分とも併せて、共有メモリの排他制御をしっかりと作りこんでおくことをお勧めします。
排他制御はミューテックスと呼ばれる同期オブジェクト(Windows APIだとCreateMutex(), .NET FrameworkではMutexクラス)によって実現することができるので、これについてもしっかりと調べておくとよいでしょう。
ちなみに、WM_COPYDATAを使う場合には、受信側が読み込むより前に次のデータが送信された場合のこととか、排他制御のこととかを全く考える必要がないので、その点ではラクと言えばラク。
->fresh homepieさん
わかりやすい例で問題点の指摘ありがとうございます。
本当に助かります。
しかも、調べるべき事柄の指摘までしていただいて。。
長年プログラムを組んでらっしゃるんですかね?
自分もfresh homepieさんのように詳しくなれるといいのですが、いつの事になるやら。。
愚痴をこぼして申し訳ありませんが、本当に覚えることがたくさんありすぎて戸惑ってしまいますね。
今までやったことがない分余計にです。
本当に助かりました。
できるだけ自分で解決していこうとは思いますが(聞くばかりだと自分の力にならないので)、また本当にわからない時は相談させてください。
ありがとうございます。
No.3
- 回答日時:
以前の質問
http://oshiete.goo.ne.jp/qa/7784868.html
では、送信側と受信側の通信は WM_COPYDATA で行い、共有メモリはあくまで第三のプログラムが読むために受信側で格納しているだけ、ということだったと記憶してますが。やっぱり共有メモリもここでの通信に使用するってことですか?
WM_COPYDATA は SendMessage を使用することを前提としたメッセージですので、PostMessage に WM_COPYDATA を渡すなどということはやってはいけません。
もし本当に PostMessage(WM_COPYDATA) を使うことを指示されたのだとすれば、その指示を出した人が WM_COPYDATA に対して間違った知識を持っているものと思われます。
実際のところ、ここでの送信側と受信側の通信に共有メモリを使い、通知イベントとして(WM_COPYDATAではなく)アプリケーション定義の独自メッセージをPostMessageで投げろ、ってことだったのでは?などと思ったりもするのですが、いかがでしょう。(それはそれで、送信プログラムが多数になった時の制御が難しそうな気もしますが)
どうしても送信側がブロックされないように WM_COPYDATA を非同期的に送信したいとなれば、SendMessage の代わりに SendMessageCallback を使えばできないこともないとは思います。
この場合、送信側のバッファをスタック領域(質問者さんの提示された「char buffer[500];」のような変数)ではなくヒープ領域(mallocとかnew[]とか)に動的に確保しておき、SendMessage の代わりに SendMessageCallback を使って送信します。
受信側の取得処理が完了すると送信側のコールバックが呼ばれるので、そこで送信バッファを解放する、という手続きを取ります。
それ以外の方法では、送信側をマルチスレッドにして、送信処理は作業スレッドに任せるとかですかね。マルチスレッドはGUIがロックされるのを回避するために良く使われる方法ですし、マルチスレッドの知識があるなら難しくはないです。
あと、そもそも提示されてるソースではbufferにテキストボックスの内容が格納されないのは、すでに別の回答で指摘されてる通りですので、まずはそちらから解決していくことをお勧めします。
->fresh homepieさん
再び回答ありがとうございます。
やっぱり共有メモリもここでの通信に使用するってことですか?
->以前の自分の見解が間違っていて、やはりここでも共有メモリを使用します。
PostMessage(WM_COPYDATA) を使うことを指示されたのだとすれば
->わかりにくい文章で申し訳ありません。
PostMessageの使用は義務付けられましたが、WM_COPYDATの使用は義務づけられていません。
ここでの送信側と受信側の通信に共有メモリを使い、通知イベントとして(WM_COPYDATAではなく)アプリケーション定義の独自メッセージをPostMessageで投げろ、ってことだったのでは?
->おっしゃるとおり、共有メモリを使用して通知イベントとしてPostMessageを投げろとのことだと自分も認識しています。
スタック領域やヒープ領域についてのこと、マルチスレッドに関して調べながらやってみます。
今は何のことかまったくわかっていませんが・・・。
まずは、ご指摘頂いた通りbufferにテキストボックスの内容を格納することから詰めていきます。
プログラムの組み方がいくらでも出てくるのが本当に羨ましいです。
貴重なご意見やヒントをありがとうございます。
また困っていたら助けてください。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# Windows Formアプリからコンソールを呼び出して文字を出力させたい 8 2023/05/09 10:53
- C言語・C++・C# C++プログラミングコードにポリモーフィズムを取り入れ方を教えてください。 2 2023/06/09 11:17
- C言語・C++・C# PC画面を録画するプログラムでdllの読み込みエラー 1 2023/04/22 08:31
- C言語・C++・C# C++初心者です stirng 2 2022/09/20 20:43
- C言語・C++・C# C# DatagridviewにExcelシートを反映するとエラーが出る 2 2023/05/06 17:12
- C言語・C++・C# このプログラミング誰か教えてくれませんか 1 2022/06/02 15:27
- UNIX・Linux AWSのEC2のZabbixユーザーでawscliコマンドが実行できない状態を解決する 1 2022/12/06 22:17
- C言語・C++・C# C++のcinの動作 5 2023/02/26 00:13
- 英語 『G19 Gen5 MOS - Modular Optic System for Gen5』 の 『 1 2023/03/05 13:37
- 英語 Modular Optic System (MOS)とは、一体どの様な物の事なのかを教えてください。 1 2023/03/03 09:52
このQ&Aを見た人はこんなQ&Aも見ています
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
RS232cを用いた送信プログラム
-
シリアル通信時のデータ受信方法
-
byte型を固定長で宣言したい
-
Winsock
-
DHCPOFFERの受信について
-
ネットワークでの受信バイト数
-
C++Builder6.0でのシリアル通信
-
赤外線センサーについて
-
VC++ 2010 メッセージが文字化...
-
TCP/IP のパケットの分断と結合...
-
パソコンに詳しい方教えて下さ...
-
xterm コピーペーストできない
-
ICH5R→ICH5R (RAID0) マザー...
-
バックアップ
-
ffastun.*って何ですか?
-
trac/wikiの記法について
-
バッチ処理でファイル整理
-
excel vba で 実行時エラー13...
-
xcopyの/dオプションについて
-
サーバーのファイルを復元
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
TCP/IP のパケットの分断と結合...
-
Outlookの「受信日時」「件名」...
-
UDP受信時の通信異常検知について
-
Outlookの「受信日時」「送信者...
-
VB2010で、シリアル通信の方法...
-
RS232cを用いた送信プログラム
-
CRC-CCITTに関しての仕様とサン...
-
DHCPOFFERの受信について
-
recv関数の戻り値について
-
winsockを使ったTCP及びUDP通信...
-
VC++メッセージの送受信につい...
-
シリアル通信時のデータ受信方法
-
PC98で232c送信winndowで受信で...
-
TCPのプログラミングで質問…と...
-
C#にてCTI。RS232Cの受信と送信...
-
VB2005でTCP/IPソケット通信で...
-
「TCPは全二重可能」の意味
-
ASP.NET C#でPOST受信
-
WinSock プロトコルスタックバ...
-
無線LAN、SIFSについて
おすすめ情報