お世話になっています、
VCからVBの*.exeを起動しています。
ShellExecuteEx(…);
問題というのは、
起動されたVBの*.exeにListBoxがあります、
このListBoxに選択されたIDをVC側に渡したいのです、
これが可能でしょうか。
もし可能とすれば、どういう関数を使えばいいでしょうか。
環境:.Net MFC使用、 Win2000, VB6.0
よろしくお願いします。
VCプログラムにメッセージを送ってもらうなり(PostMessage, SendMessage,
PostThreadMessage, etc.),
ソケット使うなり,パイプ使うなり,共有メモリ使うなり,方法はいくつもあります。
プロセス間通信と言う奴を勉強されてた方が良いと思います。
開発言語がVBだろうが、VCだろうが、実行ファイルが別になっているプログラム間で
通信するにはプロセス間通信の知識が必要です。
まあ、Windowsの場合はVCのプログラムがウインドウを持っているなら
ウインドウメッセージを使った通知が一番楽でしょうね。
方法は色々ありますから、YuOさんの意見を参考にされてはどうでしょう。
追伸:
実行ファイルが同じであっても複数回起動して別々に動作していれば、
その間でもプロセス間通信は必要になりますね。
この辺はプロセスと言う概念をきちんと理解した方が良いかもしれません。
YuOさん、PATIOさん
ご返事ありがとう.
試しにやってみたのですが、
既に起動してアプリを終了させるということですが、
hwindow = FindWindow(vbNullString, 電卓)
If hwindow = 0 Then MsgBox エラー
MsgBox hwindow
Call PostMessage(hwindow, WM_QUIT, 0, 0)
成功したのですが、
次に自分のアプリを終了させるとうまく行かないです。
(終了しない)
hwindow = FindWindow(vbNullString, アプリ)
If hwindow = 0 Then MsgBox エラー
MsgBox hwindow
Call PostMessage(hwindow, WM_QUIT, 0, 0) //ここまでOK
結果的には終了しない。
よろしくお願いします。
自分のアプリがWM_QUITメッセージを受理したとき何をしていますか?
>VCからVBの*.exeを起動しています。
>ShellExecuteEx(…);
その前にVCからVCをやってみるとわかることがあります
επιστημη さん、おとさん
ご返事ありがとう。
>自分のアプリがWM_QUITメッセージを受理したとき何をしていますか?
MFCを使っていますが、アプリ終了ということは自動的にやっているのですが、
特に、弄っていないです。
MFCの場合、ID_APP_EXITしかありません。
>その前にVCからVCをやってみるとわかることがあります
VC=>VBの*.exe ができました、ちなみに、VCのIDがVBへ送って、
VB側に受け取るもできました。
VC=>VCの*.exe(起動させる)やったことがないので、これからやってみます。
ちょっと聞きたいのは、VC(起動させる)側にIDなど受け取る関数があるのでしょうか。
ようするに、VBの場合、Command()ような関数。
よろしくお願いします。
VB側のIDを受け取ると言う意味でいっているならそもそも無理な話です。
プロセスが違うので直接受け取るような事はできないと思います。
こういう部分はプロセスと言う概念がわかっていないと多分ピンとこないと思います。
なので、「プロセスと言う概念をきちんと理解した方が良いかもしれません。」と
書いています。
別のプロセスに対して何かやってもらおうとしたらそれを伝える為に
プロセス間通信を行う必要があります。
ウインドウメッセージはあくまでも一例なのでそれで事足りるような事を
しようとしているのかどうかが分からない以上はこれ以上はアドバイスができません。
具体的にどういう事がしたいのかを説明してください。
VCのプログラムはVB側から具体的にどういう情報をもらう事ができれば良いのか?
あと、VCの掲示板でVBの関数を例に出してもVBの知識がない人間には伝わらないので
別の表現方法を考えた方が良いです。まあ、VBを知っている人間であれば伝わると
思うのですが。
私の場合はVBは触った程度しか使った事が無いのでピンと来ない方の人間です。
共有メモリを使ってVBのリストボックスのインデックスを取得する方法を試してみまし
た。なお、エラー処理等は入っていません。
また、プロセス間の同期をどうするかはよく分かりません。
データの受け渡しより、こちらの方が大変なような気がしますが・・・。
'-----------------------------------------------------------------------------
'VC++側の処理
'-----------------------------------------------------------------------------
//データメンバ(ヘッダー)に共有メモリハンドルを宣言
class C**Dlg : public CDialog
{
// インプリメンテーション
protected:
HANDLE m_hMapping; // 共有メモリハンドル
BOOL C**Dlg::OnInitDialog()
{
// TODO: 特別な初期化を行う時はこの場所に追加してください。
// 共有メモリを作成
m_hMapping = ::CreateFileMapping( INVALID_HANDLE_VALUE, NULL,
PAGE_READWRITE, 0, 1024, map_name);
// マッピングする
long* lpBuf = (long *)::MapViewOfFile( m_hMapping, FILE_MAP_ALL_ACCESS,
0, 0, 0);
// 初期化
::ZeroMemory( lpBuf, 1024);
// マッピングを解除
::UnmapViewOfFile( lpBuf);
return TRUE; // TRUE を返すとコントロールに設定したフォーカスは失われませ
ん。
}
void C*****Dlg::OnButton1()
{
// TODO: この位置にコントロール通知ハンドラ用のコードを追加してください
// 共有メモリをオープン
long* lpBuf = (long *)::MapViewOfFile( m_hMapping, FILE_MAP_READ, 0, 0, 0);
// 確認用(エディットボックスへ表示)
CEdit* myED = (CEdit *)GetDlgItem(IDC_EDIT1);
CString strBuf;
strBuf.Format(%ld,*lpBuf);
myED->SetWindowText(strBuf);
// マッピングを解除
::UnmapViewOfFile( lpBuf);
}
'-----------------------------------------------------------------------------
'VB側の処理
'-----------------------------------------------------------------------------
Private hFileMap As Long
Private lpFileMap As Long
Private Const FILE_MAP_WRITE = &H2
Private Declare Function MapViewOfFile Lib kernel32 _
(ByVal hFileMappingObject As Long, _
ByVal dwDesiredAccess As Long, _
ByVal dwFileOffsetHigh As Long, _
ByVal dwFileOffsetLow As Long, _
ByVal dwNumberOfBytesToMap As Long _
) As Long
Private Declare Function OpenFileMapping _
Lib kernel32 Alias OpenFileMappingA _
(ByVal dwDesiredAccess As Long, _
ByVal bInheritHandle As Long, _
ByVal lpName As String _
) As Long
Private Declare Sub CopyMemory Lib kernel32 Alias RtlMoveMemory _
(ByRef Destination As Any, _
ByRef Source As Any, _
ByVal Length As Long)
Private Declare Function FlushViewOfFile Lib kernel32 _
(ByRef lpBaseAddress As Any, _
ByVal dwNumberOfBytesToFlush As Long _
) As Long
'********************************
'共有メモリへ書き込み
'********************************
Private Sub List1_Click()
Dim id As Long
id = List1.ListIndex
hFileMap = OpenFileMapping(FILE_MAP_WRITE, 0, map_name)
lpFileMap = MapViewOfFile(hFileMap, FILE_MAP_WRITE, 0&, 0&, 0&)
CopyMemory ByVal (lpFileMap), id, Len(id)
FlushViewOfFile ByVal lpFileMap, Len(id)
End Sub
PATIO さん、さやぴ さん
ご返事ありがとう。
返事が遅かったすみませんでした。
さやぴ さんが書いたコードを確認しました。
問題がなくListのIndexが取得できました。
>また、プロセス間の同期をどうするかはよく分かりません。
その辺私もわかりません、これからやってみようと思っています。
>データの受け渡しより、こちらの方が大変なような気がしますが・・・。
確かに。
最後、さやぴ さんのすばらしいコードをいただいて、
ほんとに、ありがとうございました。
これから、VCとVBを融合にしていく、頑張ります。
始めて書き込ませていただきます。Atata!!と申します。
既に解決済みですが、VB側のソースが修正可能であるなら、
オートメーションを使用する方法が簡単で良いかと思います。
めんどくさいのでそのままソースを貼り付けさせて貰いますが、以下のようになります。
'-----------------------------------------------------------------------------
'VB側の処理
'Form上にList1って名前のリストボックスを貼り付けて下さい。
'-----------------------------------------------------------------------------
Option Explicit
Private Const ACTIVEOBJECT_STRONG As Long = 0
Private Const ACTIVEOBJECT_WEAK As Long = 1
Private Const APPLICATION_CLSID As String = {3eca5a91-5803-4f6b-95a7-
81a0f64c0b08}
Private Type Guid
Data1 As Long
Data2 As Integer
Data3 As Integer
Data4(0 To 7) As Byte
End Type
Private Declare Function CLSIDFromString Lib OLE32.DLL (ByVal lpsz As String,
ByRef pclsid As Guid) As Long
Private Declare Function RegisterActiveObject Lib OLEAUT32.DLL (ByVal punk As
Object, ByRef rclsid As Guid, ByVal dwFlags As Long, ByRef pdwRegister As Long)
As Long
Private Declare Function RevokeActiveObject Lib OLEAUT32.DLL (ByVal
dwRegister As Long, ByVal pvReserved As Long) As Long
Private register_id As Long
Private Sub Form_Load()
Dim hr As Long
Dim clsid As Guid
Call CLSIDFromString(StrConv(APPLICATION_CLSID, vbUnicode), clsid)
hr = RegisterActiveObject(Me.List1, clsid, ACTIVEOBJECT_STRONG, register_id)
If hr < 0 Then
MsgBox 登録失敗
End If
End Sub
Private Sub Form_Unload(Cancel As Integer)
Call RevokeActiveObject(register_id, 0)
End Sub
//-----------------------------------------------------------------------------
//VC++側の処理
//-----------------------------------------------------------------------------
#include <ole2.h>
wchar_t APPLICATION_CLSID[] = L{3eca5a91-5803-4f6b-95a7-81a0f64c0b08};
int main(int argc, char* argv[])
{
CLSID clsid;
HRESULT hr;
IUnknown* unknown;
IDispatch* dispatch;
LPOLESTR propertynames[] = {LListIndex};
DISPID dispid;
DISPPARAMS dispparams = {NULL, NULL, 0, 0};
VARIANT result;
OleInitialize(NULL);
CLSIDFromString(APPLICATION_CLSID, &clsid);
hr = GetActiveObject(clsid, NULL, &unknown);
if (SUCCEEDED(hr))
{
hr = unknown->QueryInterface(&dispatch);
if (SUCCEEDED(hr))
{
hr = dispatch->GetIDsOfNames(GUID_NULL, propertynames, 1, 0,
&dispid);
if (SUCCEEDED(hr))
{
VariantInit(&result);
hr = dispatch->Invoke(dispid, GUID_NULL, 0,
DISPATCH_PROPERTYGET, &dispparams, &result, NULL, NULL);
}
if (SUCCEEDED(hr))
{
VariantClear(&result);
}
dispatch->Release();
}
unknown->Release();
}
OleUninitialize();
return 0;
}
この手法はレジストリを使用しなくても良いため私が好んで使用する手法ですが、
本来はVB自身の機能でオートメーションオブジェクトを公開する方が良いと思います。
問題となる同期はCOMのプロセス間通信部分が勝手にやってくれます。
逆にVB側で重たい処理をやってるとVC++から呼び出した時に固まりますが・・・。
まぁ回避方法はいろいろあります。
投稿してから気づきましたがVB側の改行されてるところは、
コンパイルエラーが出ないように適当に整形してください。
VC++側のどこで値が取れてるか示す部分を忘れてましたが、
hr = dispatch->Invoke(dispid, GUID_NULL, 0,
DISPATCH_PROPERTYGET, &dispparams, &result, NULL, NULL);
の後で result に値が帰ってきます。デバッガで中身を確認してみて下さい。
久々によそのサイトに投稿するんで、中々抜けが多いもんですわ。
Atata!! さん
ご返事ありがとう.
サンプルありがとう。
確認したのですが、ListIDを取得できました。
コードを見たら、びっくりしました、
自分の知識の範囲外でした。
Atata!! さんの[HomePage]をざっと見ました、
今書いたコードはOLEということでしょうか。
(汗)
よろしくお願いします。