• ベストアンサー

Delphi6 DLL内でのメモリ共有(?)

こんにちは、honiyonです。  複数アプリケーションからそれぞれコールバック関数を登録してもらい、状況に応じてそれぞれのコールバック関数を呼び出す、というDLLを作成しています。  しかし現在、呼び出しアプリケーションごとにメモリ空間が独立してしまい、コールバック情報を同一空間内で管理出来ずに困っています。  旧VerのDelphiで16bit DLLなら、interface部に定義した変数、オブジェクトはDLL内で同一空間内で共有出来るようですが、これをDelphi6 32bitDLLで行う事は不可能でしょうか? もしくは、その他の方法で独立メモリ空間を作らないようにする方法はありますでしょうか?  不可能な場合、CreateFileMappingが次に有効な手段として候補に挙がると思います。CreateFileMappingで管理クラスのポインタを渡してクラス共有というのは現実的な手法でしょうか?  よろしくお願いいます(..

質問者が選んだベストアンサー

  • ベストアンサー
  • hope10
  • ベストアンサー率48% (17/35)
回答No.1

Delphiは無知なので一般的な意見です。 メモリマップドファイル(共有メモリ)は現実的だと思います。特に16->32bit移行時には良く使われた手法ではないかと思います。 片やDLLの共有領域はVC++等では共有セグメントを指定すれば可能ですが、Delphi(特にLinker)でどのような扱いになるのか??? Win32の寿命、その他から、個人的には共有メモリを推します。

その他の回答 (1)

  • chokuto
  • ベストアンサー率40% (2/5)
回答No.2

私もDelphiは知らないので、一般的な意見を…。 CreateFileMapping による共有メモリが有効だと思いますが、「管理クラスのポインタを渡して」という方法でうまくいくのかどうかは分かりません。必要なデータだけを共有メモリにおくべきだと思います。 複数アプリからということなので、アプリごとに異なるデータをやり取りするのなら、ウィンドウメッセージを使うという方法もあります。対象アプリにはウィンドウハンドルを登録してもらって、独自のメッセージコード(WM_USER以降)やWM_COPYDATAメッセージなどでデータをやり取りするのも一つの手です。Delphiでメッセージ処理がどのように行われているのかはよく知りませんが…。

honiyon
質問者

補足

こんにちは、honiyonです。  お礼が遅くなり申し訳ありませんm(_ _)m  失礼ながらここにまとめてお礼させて頂きます。  調査したところ、メモリ空間が完全に独立してしまい、ポインタを共有したところで、渡された側でデータを参照できませんでした。  今回共有したかったデータはクラス型であったり、少々無理を感じたので設計そのものを見直す事にしました。  ご回答有難うございました(。。  

関連するQ&A

  • DLLはアドレスを共有する?

     CでWindowsプログラミングの勉強をしています.そこでDLLについての質問なのですが,ある本で「DLLは複数のプログラムが共有し,ひとつのDLLはひとつしかメモリ上に配置されない」という文章を読みました.プログラムはDLLの配置されてあるアドレスを元に,DLL内の関数を実行するのだと考えれば納得はいきましたが,よく考えたらおかしいと思いました.  それは「変数,関数」の取り扱いはどうなるのか,ということです.C言語で物理メモリアドレスを見る方法がわからないので何とも言えませんが,試しに,DLL内に次のような関数MyFunctionを用意し,このDLLを取り込むプログラムを同時に2つ走らせ,MyFunctionを何度も呼んでDll1_Variableの値を増加させていきました. LIBSPEC int MyFunction(LPCWSTR str) { static int Dll1_Variable=0; Dll1_Variable++; _tprintf(_T("%d\n"),Dll1_Variable); return 0; }  もしDLLが共有されているのならば,Dll1_Variableの値は2つのプログラムから同時に更新されると思うのですが,実際には2つのプログラム上でまったく独立(つまり各プログラムごとに1,2,3,...というように)増加していきました.こうなるとDLLって本当に共有されているのかという,不信感が出てきてしまいます.  なんだか重大な勘違いをしている気がしてなりませんが,上記のプログラムがなぜ独立に変数が増加していくのか,「DLLが共有される」というのは実際にはどういう仕組みになっているのか,ご存知の方がいらっしゃったらご教授ください.わかりにくい質問ですみません.よろしくお願いします.

  • C#で作成したDLLをDelphiで呼ぶ方法

    プログラミング初心者です。 以下の内容について、どなたか教えてください。 Visual studio 2010(C#のフォームアプリケーション)とCOM(ActiveX Tool bar)で作成されたフォームをDelphiで呼び出すことは可能でしょうか。 上記の内容を試験的に作成し(Visual studio 2010C#のフォームにCOMから参照したToolbarを貼り付けた物)、プロジェクトの出力方式をクラスライブラリに変更して、DLLの作成までは行えました。しかし、その先のDelphiからの呼び出し方がわかりません。 上記のDLLを用いてDelphiから呼び出す方法をご存知の方がいれば、教えてください。 なお現在の開発環境は以下の通りです。 Visual Studio 2010(C#) Delphi XE2(Trial) ご教授のほど、よろしくお願い致します。

  • Delphi で作成中 DLL の中で ProcessMessages を行うには?

    ソケット通信を行うDLLをDelphiで作っています。クライアント側になるので、まずは普通のフォームで作成し、動作を確認したのでフォームを除去してDLLに移行しています。 TClientSocket を利用しているので、たとえば通信終了時の OnSocketDisconnect 等、ソケット通信に関連するイベントに応答しなければならないのですが、DLLとして外部からコールされるとき、イベントをどのように待ったらよいのか分かりません。 Application.ProcessMessages が使えれば、それで何とかなりそうなのですが、他の手段はあるでしょうか。 もしくは、TClientSocket 等のコンポーネント以外の方法でソケット通信を実現すれば良いのかも知れませんが、どのような方法があるのか分かりません。 何かアドバイスをいただければ幸いです。

  • CWndを使うDLL

    質問1 CWndのサブクラスを作りたいDLLは、以下のどのDLLとして作成すれば良いでしょうか? ・Win32 DLL ・MFC共有DLL ・MFC拡張DLL ちなみに、このDLLは、必ずしもMFCで作成されたアプリケーションでロードされるとは限りません。 質問2 上記選択でMFCになった場合、MFCのライブラリは動的リンクと静的リンクのどちらになるのでしょうか? 自分で選択できるのであれば、その方法を教えてください。 質問3 上記選択で静的リンクになった場合。 MSDNのページで調べると以下のような制限があるとのことですが、具体的には、こういうことでしょうか? ・DLL内で確保したメモリのポインタを上位からもらってもいけないし、上位へ返してもいけない。 ・MFC オブジェクト(CWndサブクラスへのポインタなど)を上位からもらってもいけないし、返してもいけない。 --- MSDN引用ここから 「レギュラー DLL 内のメモリ割り当てはすべて、DLL の範囲内に収める必要があります。 したがって、以下のポインタを呼び出し側の実行可能ファイルとやり取りすることはできません。 ・MFC オブジェクトへのポインタ ・MFC によって割り当てられたメモリへのポインタ --- MSDN引用ここまで よろしくお願いします。

  • Delphi6でVB.NETで作成のDLL呼出

    VisualSutudio2005で作成され提供されているDLLをDelphi6から呼びだしたいと思っています。 提供ファイルとしてあるのは以下のものです。 ・DLLファイル本体 ・XMLファイル 直接は呼びだせない(?)と思ったので、 VB.NETでDLLを作って間に入れて、 下のように呼び出せばいいのかなと考えています。 Delphi6で作成のEXE → VB.NETで作成のDLL(COM登録?) → 対象のDLL まずはDelphi6のEXE→VB.NETのDLLの部分を作って試してみたですが Delphi6のEXEの起動時にエラーとなってしまいます。 「アプリケーションの初期化に失敗しました」 ネットなどで調べてみて作り方は下記のようにしました。 <呼ばれる側:VB.NETのDLL> 1.COMクラスを作る。   ・COM参照可能の設定にした。 (タイプライブラリが作成され、レジストリへのCOM登録は自動でされる?) 2.作成したDLLはCドライブ直下に置いた。 ※下の*****は自動作成された固定値が入っています。  また見やすくするためここでは半角空白を全角空白に変えています。 -------------------------------------------------------------------- Imports System.Windows.Forms <ComClass(Middle_Dll.ClassId, Middle_Dll.InterfaceId, Middle_Dll.EventsId)> _ Public Class Middle_Dll #Region "COM GUID"   ' これらの GUID は、このクラスおよびその COM インターフェイスの COM ID を   ' 指定します。この値を変更すると、   ' 既存のクライアントはクラスにアクセスできなくなります。   Public Const ClassId As String   = "**************************"   Public Const InterfaceId As String = "**************************"   Public Const EventsId As String  = "**************************" #End Region   ' 作成可能な COM クラスにはパラメータなしの Public Sub New() を指定しなければ   ' なりません。これを行わないと、クラスは COM レジストリに登録されず、   ' CreateObject 経由で   ' 作成できません。   Public Sub New()     MyBase.New()   End Sub   Public Sub DispMsg()     Dim MsgRet As MsgBoxResult     MsgRet = MessageBox.Show("VB.NET DLLより表示!", "確認メッセージ", MessageBoxButtons.YesNo, MessageBoxIcon.Information)   End Sub End Class --------------------------------------------------------------------- <呼び出し側:Delphi6のEXE> 1.タイプライブラリの取り込み設定で登録したDLLを選択し、   「コンポーネントラッパーの作成」にチェックを入れてインストールを実行。 --------------------------------------------------------------------- unit Unit1; interface uses  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,  Dialogs, StdCtrls,OleCtnrs,ComObj, OleServer; type  TForm1 = class(TForm)   Button1: TButton;   Edit1: TEdit;   procedure Button1Click(Sender: TObject);  private   { Private 宣言 }  public   { Public 宣言 }  end; var  Form1: TForm1;  //----------  //静的呼出  //----------  procedure DispMsg();Stdcall; external 'c:\Middle_Dll.dll' name 'DispMsg'; implementation {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); begin  //----------  //静的呼出  //----------  DispMsg(); end; end. ----------------------------------------------------------------- Delphi6のEXEはすでにあるものなので、 呼び出し元はDelphi6から変えられませんが、 呼び出し先はC#やC++でも構いません。 (1)Delphi6のEXE→VB.NETのDLLの呼び出しは可能でしょうか? (2)可能でしたら不具合と思われる箇所はどこでしょうか? (3)この方法より良いと思われる方法はありますでしょうか? DLLを作った事がないので見よう見まねで作っています。 気になる点やアドバイス程度でも構いませんので、 どうかよろしくお願いいたします。 == 開発環境 == WindowsXP SP3 Delphi6 Enterprise SP2 VisualSutudio2005 ProffesionalEdition 評価版 .NET Framework 1.1~3.5

  • 共有DLLの参照方法

    共有DLLのインストールパスが変わる(Windowsがインストールされたパーティションのマッピングの違い,X86とX64の違い,ユーザーがカスタムインストールしているなど) EXEとの相対パスが変わる(ZIPで圧縮されている場合の回答位置など) DLLの種類やその中に含まれるクラスなどの定義は変わらない レジストリなどを介してファイルパスはわかる という事になるわけですがこういった場合の参照はどのように追加すればよいのでしょうか? どぼん氏のプラグイン機能を持つアプリケーションを作成するのような実装では インターフェースをEXEか別のDLLでインターフェースをクラス分全て持たなければならない インターフェースを持つDLLと共有DLL、インターフェースを持つDLLとEXEの双方の相対パスが変えられない またはインターフェースを持つDLLの絶対パスが変えられない といった問題が回避できませんでした。 環境はWindows Vista x64+Visual Studio 2005です。

  • 異なるexeから参照しているdllの変数は実行時のメモリ領域として独立的か?

    結論から質問内容を言うと、 異なるexeから参照しているdllの変数は実行時のメモリ領域として独立的か? 具体的には、 A.exeと、B.exeの両方で参照している Common.dllに定義しているクラスの staticなフィールドは、A.exe実行時のメモリ領域と、 B.exe実行時のメモリ領域と、完全に別で独立状態 であることを前提にしているのですが。。。 これは本当に真なのかを確認させてください。 あたりまえじゃねーかバカ野郎っていわれそうですが ちょっと、そこ間違えると後で、痛いので、 念押しで再確認お願いします。 <質問に至った経緯> Delphi3.0からVB.NET2003(2005未対応のコンポーネントを使用する諸事情があったから) にシステム移行の案件があり、 工数を避けません。現在、開発方針を検討中で調査していると、デルファイプロジェクトAと、 デルファイプロジェクトBで、Commonという名前の フォルダにあるソースを共有していて、 A.exeとB.exeを作っていました。 特に共通部分をdllにしていたりしていませんが。 VB.NETでそれは、きついので、 Commonにあるソースだけ、集めたCommon.dllを作る プロジェクトを作り、Aプロジェクト、BプロジェクトがCommon.dllを参照するやり方を検討しました。 Common.dllには、たくさんグローバルな変数が定義されていたので、 グローバルなデータは、もともとのソースファイルごとにクラスを 作ってそこにスタティックなフィールドとして宣言していく。それをAや、Bのプロジェクトのソースで 使うが、もともと、デルファイがexeが完全にわかれていたので、VBでdllに分けた結果、実行時にメモリも 共有されると、意図した動きをしてくれない懸念が あるので、それはないのかどうかを確認したかった。 ########################################### 以上です。

  • DLL作成について

    DLL作成の機会がいろいろ調べているのですが、教えていただきたいことがあります。 1.インポートライブラリについて  Windowsで暗黙的リンクでDLLをリンクする場合、  インポートライブラリを利用するようですが、  これは、DLL内のポインタと関数名を紐付けるような  役割だと想定しています。  仮に関数等ヘッダーで公開されている部分以外で  DLLを更新した場合、インポートライブラリも  再リンクするような場面があるのでしょうか。  特に再リンクしなくてもDLLの更新が反映されたので・・ 2.DLLのクラスの継承について  DLL内に作成したクラスを継承することは不可能ですかね。  DLLが更新された場合、インスタンスのイメージが違うため  newやdeleteの処理で当初リンクしたインスタンスのイメージで  行いますよね。

  • [C#][FX]DLLを利用した共有メモリの動作

    こんにちわ。 外国為替取引のFXに利用するプログラムを作成しています。 その中で、 C#のプログラムAと MQLという言語によるプログラムBにおいて、 共有メモリ読み書きを行うDLLを利用して、 (1)Aの結果を共有メモリに書き込み→Bで受け取って処理。 (2)Bの結果を共有メモリに書き込み→Aで受け取って処理。 という仕組みを作成しています。 (2)はできたのですが、(1)がうまくいきません。 知見をお持ちの方アドバイスいただけませんでしょうか。 以下詳細でございます。 ●相談内容 共有メモリ書き込み時に以下エラーが発生し、書き込みができない。 「保護されているメモリに読み取りまたは書き込み操作を行おうとしました。他のメモリが壊れていることが考えられます。」 ●ソース(一部抜粋。InitializeとRunは基盤システムからコールされます。) 【C#ソース】 using System.Runtime.InteropServices; using System; [DllImport("MemMap.dll", SetLastError = true, CharSet = CharSet.Auto)] public static extern string SetMemString(string tag, string msg); public bool Initialize() { try{ Console.Write("try01"); SetMemString("TEST", "1"); Console.Write("try02"); SetMemMethod(); }catch(Exception e){ Console.Write(e.Message); Console.Write(e.StackTrace); } return true; } public void SetMemMethod(){ SetMemString("TEST", "2"); } public void Run(){ try{ Console.Write("try03"); SetMemString("TEST", "3"); }catch(Exception e){ Console.Write(e.Message); Console.Write(e.StackTrace); } } } } 【コンソール】 try01 保護されているメモリに読み取りまたは書き込み操作を行おうとしました。他のメモリが壊れていることが考えられます。 場所 test.Main.SetMemString(String tag, String msg) 場所 test.Main.Initialize() try03 保護されているメモリに読み取りまたは書き込み操作を行おうとしました。他のメモリが壊れていることが考えられます。 場所 test.Main.SetMemString(String tag, String msg) 場所 test.Main.Run( 【DLL】 MT4_EXPFUNC const char* __stdcall SetMemString(char *tag,char *msg) { /*static*/ string ret = ""; bool create = false; HANDLE hMap = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, tag); if (!hMap) { hMap= CreateFileMapping((HANDLE)0xFFFFFFFF , NULL , PAGE_READWRITE , 0 , 1024 , tag); q.push(hMap); create = true; } LPSTR strAllCmd =(LPSTR)MapViewOfFile(hMap , FILE_MAP_WRITE , 0 , 0 , 0); lstrcpy(strAllCmd , msg); FlushViewOfFile(strAllCmd,0); UnmapViewOfFile(strAllCmd); if(!create) CloseHandle(hMap); return(ret.c_str()); } ●詳細 try01直後の初期化メソッド(Initialize)で直接コールするSetMemStringは問題なく出来ており、プログラムB側で読むことができていますが、 try02直後の初期化メソッド(Initialize)でコールするメソッドの中のSetMemStringと try03直後のメイン処理(Run)の中のSetMemString でエラーが発生します。 try02はソースの綺麗さを保つために別メソッドに切り出したいだけなので、 最悪初期化メソッドに直書きすればよいですが、 メイン処理なので、try03でエラーが発生するのはなんとしても解決したいです。 try01で呼べていることからDllImportのスコープがうまくできていないのでは? と考えています。 継承元のExpertクラスはソースが隠蔽されていて、わかりませんが、 何かアドバイスいただけませんでしょうか。よろしくお願いします。

  • DLLが正しく呼び出せません (ToT)

    こんにちは。よろしくお願いします。 環境は、WindowsXP Access2000/VBA にてプログラミングをしています。 現在、表題の「DLLが正しく呼び出せません」エラーに泣かされています。。。。 どなたかもし心当たりなどありましたらぜひアドバイスを下さい。 VBAにてシステムを作成していますが、その中で、普通に自分で書いた関数を 普通に?呼び出しているだけなのですが、表題のエラーが頻発してしまい困っています。 別に、外部DLLをDeclareしてそれを呼び出した時に出ている、という事ではないです。 普通に自分で書いた関数を呼び出すだけなんですが、ある関数を呼び出すと、 返ってくる時にこのエラーが発生するものがあります。(SubでもFunctionでも) 引数の型や戻り値の型は、呼び出し側と整合が取れています。(確実に一致しています) まったく原因がわからないので、例えばエラーの出た関数がSubの場合は 一応 Call をつけて呼び出してみたりするとその場はエラーがなくなったりして でも、またその関数の中を編集したりすると、いつのまにかまた その関数を呼び出した時に表題のエラーがでたりします。 もちろんコンパイルエラーはありませんし、SetしてNothingを忘れてメモリを壊している という事などもないつもりです。 (エラーのでる関数ではそもそもSetなどを使っていませんし) DLLの関数を呼び出すのではなく普通に標準モジュールなどに書いた自前の関数の呼び出しで 表題のエラーがでる原因として、なにか考えられる事はあるのでしょうか。 実際のソースを載せれないので申し訳ないですが、一般的な情報として 「DLLが正しく呼び出せません」エラーの原因となる事をどのような事でもけっこうですので 教えていただければ、と思います。 どうかよろしくお願いいたします。

専門家に質問してみよう