Q&A

  • [긴급질문]DLL내의 공유메모리가 아닌 실행화일에서의 자료공유
안녕하세요.

Delphi를 사용하는 초보 홍진혁입니다.



제가 구현하려고 하는 것은 Main Execution의 어떤 배열을 공유메모리로 사용하려는 것입니다.

즉, DLL내에서 정의한 공유메모리를 사용하려는 것이 아니라 어떤 실행화일에서 정의된 배열을

공유메모리로 하고 싶은 것입니다. 2개의 실행 프로그램의 자료공유를 DLL내의 전역 공유메모리로 하는 것이 아니라,

한 실행프로그램의 배열을 공유 메모리로 하여 서로의 자료를 공유하고 싶은 것입니다.

그래서 시도한 방법이 실행화일에서 정의된 배열의 포인터를 DLL함수의 인자로

DLL에 넘겨주어서, DLL내의 전역변수에 그 배열의 포인터를 저장하여 내가 원하는 값을 그 포인터에

집어넣기만 하면 그것이 바로 공유메모리와 같은 역활을 하는 것이 아닌가 하는 것입니다.

이를 위해 아래와 같이 프로그램을 구현 하였습니다.

그러나,

Project TestDll.exe raised execution class EAccessViolation with message 'Access

violation at address C35DF8EB. Read of address C35DF8EB'. Process stopped. Use Step

or Run to continue.

같은 에러 메세지가 뜹니다.



아래 DLL 소스의

procedure KeepGlobalPointer( Ptr : PARRAY_CHAR); StdCall;

begin

Keep_ShareDllPtr := Ptr; //<--- Keep_ShareDllPtr이라는 전역변수에 값을 저장하고 싶은것것입니다.

end;

부분에서 만일 Ptr을 Ptr := Keep_ShareDllPtr;로 하면 (즉, DLL내의 전역변수의 포인트를 가져오면) 애러가 뜨지 않습니다.

그러나 DLL내의 전역변수의 포인터에 값을 대입하면 애러가 뜹니다.

이 문제가 해결이 되지 않아 며칠을 고민하다가 마지막으로 고수님들의 지도를 바라는 수밖에 없었습니다.



부탁드립니다.





[어떤 실행화일의 소스]

unit TestDll_u;



interface



uses

Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,

StdCtrls, ExtCtrls;

type

ARRAY_CHAR = array[1..1800000] of char;

PARRAY_CHAR = ^ARRAY_CHAR;



type

TForm1 = class(TForm)

Button1: TButton;

Timer1: TTimer;

procedure Button1Click(Sender: TObject);

procedure FormCreate(Sender: TObject);

procedure Timer1Timer(Sender: TObject);

private

{ Private declarations }

public

{ Public declarations }

end;

type

RM_REAL100 = array [1..450000] of single;

PRM_REAL100 = ^RM_REAL100;



var

Form1: TForm1;

start : boolean;

Save_SV : RM_REAL100;

procedure KeepGlobalPointer( Ptr : pointer ); external 'MAAP_SHARE.dll';



implementation



{$R *.DFM}



procedure TForm1.Button1Click(Sender: TObject);

begin

Timer1.Enabled := not Timer1.Enabled;



Button1.Caption := FloatToStr(Save_SV[23]);

end;



procedure TForm1.FormCreate(Sender: TObject);

begin

Timer1.Interval := 100;

Timer1.Enabled := false;

end;



procedure TForm1.Timer1Timer(Sender: TObject);

var

Ptr_R1 : PRM_REAL100;

begin

ptr_R1 := Addr(Save_SV);

KeepGlobalPointer(ptr_R1); // <------Save_SV를 공유메모리로 하고 싶은 것이지요!!!

end;



end.



다음은 KeepGlobalPointer함수가 정의된 DLL Library 소스입니다.



library MAAP_SHARE;



uses

ShareMem,

Windows,

SysUtils,

Classes;



type

P_REAL = ^single;

ARRAY_CHAR = array[1..1800000] of char;

PARRAY_CHAR = ^ARRAY_CHAR;

ARRAY_P_REAL= array [1..10000] of P_REAL;

ARRAY_INT= array [1..10000] of integer;



type

RM_REAL100 = array[1..450000] of single;

PRM_REAL100 = ^RM_REAL100;



var

Keep_ShareDllPtr : PARRAY_CHAR;

global_addr : ARRAY_P_REAL;

global_size : ARRAY_INT;

global_num : integer; // 참조하고자 하는 array의 갯수



procedure SV_SET; StdCall;

var

i, j : integer;

Dest_Chr : ARRAY_CHAR;

begin

j := 1;



for i := 1 to ( global_num ) do

begin

move(global_addr[i]^, Keep_ShareDllPtr^[j],global_Size[i]);

// <--- Keep_ShareDllPtr의 내용에 저장하려고 합니다.

j := j + global_Size[i];

end;



end;



procedure SV_GET; StdCall;

var

i, j : integer;

Dest_Chr : ARRAY_CHAR;

begin

j := 1;

for i := 1 to ( global_num ) do

begin

move(Keep_ShareDllPtr^[j], global_addr[i]^, global_size[i]);

// <--- Keep_ShareDllPtr의 내용을 가지고 오려고 하는 것입니다.

j := j + global_size[i];

end;

end;



procedure AddPointer( Ptr : P_REAL; Size : Integer ); StdCall;

begin

inc(global_num);

global_addr[global_num] := ptr;

global_size[global_num] := 4 * Size;

end;



procedure KeepGlobalPointer( Ptr : PARRAY_CHAR); StdCall;

begin

Keep_ShareDllPtr := Ptr; //<--- Keep_ShareDllPtr이라는 전역변수에 값을 저장하고 싶은것것입니다.

end;



procedure OpenSharedData;

var

i : integer;

begin



global_num := 0;



for i := 1 to 10000 do begin

global_size[i] := 0;

end;



end;



procedure CloseSharedData;

begin

end;



procedure DLLEntryPoint(dwReason: DWord);

begin

case dwReason of

DLL_PROCESS_ATTACH: OpenSharedData;

DLL_PROCESS_DETACH: CloseSharedData;

end;

end;



exports

AddPointer, SV_SET, SV_GET, KeepGlobalPointer;



begin

{ First, assign the procedure to the DLLProc variable }

DllProc := @DLLEntryPoint;

{ Now invoke the procedure to reflect that the DLL is attaching

to the process }

DLLEntryPoint(DLL_PROCESS_ATTACH);

end.

1  COMMENTS
  • Profile
    최용일 2001.05.02 13:32
    안녕하세요. 최용일입니다.



    님이 하실려는 것은 Win32(Windows 95이상)에서는 불가능합니다. Win16이라면 가능하지만...



    Win32에서는 각각의 프로세스마다 독립된 가상적인 4GB의 주소공간을 가지고 있습니다. 즉, 다



    른 주소공간의 데이터나 코드를 수정할수 없습니다. 때문에 다른 프로세스의 주소는 현재 프로



    세스내에서는 아무런 의미가 없습니다.



    Win32에서 프로그램간의 데이터교환하는 방법은 직접 포인터를 써서 넘겨주지 않고, 클립보



    드, DDE, OLE, WM_COPYDATA, 메모리맵드파일등을 이용합니다. 이중에서 메모리맵드파일을 이



    용하는 것을 추천합니다. 젤 쉬우면서 read/write 둘 다 가능하니까요. 검색해보시면 예제도 있



    을겁니다...



    ^^ 항상 즐코하세요...



    홍진혁 wrote:

    > 안녕하세요.

    > Delphi를 사용하는 초보 홍진혁입니다.

    >

    > 제가 구현하려고 하는 것은 Main Execution의 어떤 배열을 공유메모리로 사용하려는 것입니다.

    > 즉, DLL내에서 정의한 공유메모리를 사용하려는 것이 아니라 어떤 실행화일에서 정의된 배열을

    > 공유메모리로 하고 싶은 것입니다. 2개의 실행 프로그램의 자료공유를 DLL내의 전역 공유메모리로 하는 것이 아니라,

    > 한 실행프로그램의 배열을 공유 메모리로 하여 서로의 자료를 공유하고 싶은 것입니다.

    > 그래서 시도한 방법이 실행화일에서 정의된 배열의 포인터를 DLL함수의 인자로

    > DLL에 넘겨주어서, DLL내의 전역변수에 그 배열의 포인터를 저장하여 내가 원하는 값을 그 포인터에

    > 집어넣기만 하면 그것이 바로 공유메모리와 같은 역활을 하는 것이 아닌가 하는 것입니다.

    > 이를 위해 아래와 같이 프로그램을 구현 하였습니다.

    > 그러나,

    > Project TestDll.exe raised execution class EAccessViolation with message 'Access

    > violation at address C35DF8EB. Read of address C35DF8EB'. Process stopped. Use Step

    > or Run to continue.

    > 같은 에러 메세지가 뜹니다.

    >

    > 아래 DLL 소스의

    > procedure KeepGlobalPointer( Ptr : PARRAY_CHAR); StdCall;

    > begin

    > Keep_ShareDllPtr := Ptr; //<--- Keep_ShareDllPtr이라는 전역변수에 값을 저장하고 싶은것것입니다.

    > end;

    > 부분에서 만일 Ptr을 Ptr := Keep_ShareDllPtr;로 하면 (즉, DLL내의 전역변수의 포인트를 가져오면) 애러가 뜨지 않습니다.

    > 그러나 DLL내의 전역변수의 포인터에 값을 대입하면 애러가 뜹니다.

    > 이 문제가 해결이 되지 않아 며칠을 고민하다가 마지막으로 고수님들의 지도를 바라는 수밖에 없었습니다.

    >

    > 부탁드립니다.

    >

    >

    > [어떤 실행화일의 소스]

    > unit TestDll_u;

    >

    > interface

    >

    > uses

    > Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,

    > StdCtrls, ExtCtrls;

    > type

    > ARRAY_CHAR = array[1..1800000] of char;

    > PARRAY_CHAR = ^ARRAY_CHAR;

    >

    > type

    > TForm1 = class(TForm)

    > Button1: TButton;

    > Timer1: TTimer;

    > procedure Button1Click(Sender: TObject);

    > procedure FormCreate(Sender: TObject);

    > procedure Timer1Timer(Sender: TObject);

    > private

    > { Private declarations }

    > public

    > { Public declarations }

    > end;

    > type

    > RM_REAL100 = array [1..450000] of single;

    > PRM_REAL100 = ^RM_REAL100;

    >

    > var

    > Form1: TForm1;

    > start : boolean;

    > Save_SV : RM_REAL100;

    > procedure KeepGlobalPointer( Ptr : pointer ); external 'MAAP_SHARE.dll';

    >

    > implementation

    >

    > {$R *.DFM}

    >

    > procedure TForm1.Button1Click(Sender: TObject);

    > begin

    > Timer1.Enabled := not Timer1.Enabled;

    >

    > Button1.Caption := FloatToStr(Save_SV[23]);

    > end;

    >

    > procedure TForm1.FormCreate(Sender: TObject);

    > begin

    > Timer1.Interval := 100;

    > Timer1.Enabled := false;

    > end;

    >

    > procedure TForm1.Timer1Timer(Sender: TObject);

    > var

    > Ptr_R1 : PRM_REAL100;

    > begin

    > ptr_R1 := Addr(Save_SV);

    > KeepGlobalPointer(ptr_R1); // <------Save_SV를 공유메모리로 하고 싶은 것이지요!!!

    > end;

    >

    > end.

    >

    > 다음은 KeepGlobalPointer함수가 정의된 DLL Library 소스입니다.

    >

    > library MAAP_SHARE;

    >

    > uses

    > ShareMem,

    > Windows,

    > SysUtils,

    > Classes;

    >

    > type

    > P_REAL = ^single;

    > ARRAY_CHAR = array[1..1800000] of char;

    > PARRAY_CHAR = ^ARRAY_CHAR;

    > ARRAY_P_REAL= array [1..10000] of P_REAL;

    > ARRAY_INT= array [1..10000] of integer;

    >

    > type

    > RM_REAL100 = array[1..450000] of single;

    > PRM_REAL100 = ^RM_REAL100;

    >

    > var

    > Keep_ShareDllPtr : PARRAY_CHAR;

    > global_addr : ARRAY_P_REAL;

    > global_size : ARRAY_INT;

    > global_num : integer; // 참조하고자 하는 array의 갯수

    >

    > procedure SV_SET; StdCall;

    > var

    > i, j : integer;

    > Dest_Chr : ARRAY_CHAR;

    > begin

    > j := 1;

    >

    > for i := 1 to ( global_num ) do

    > begin

    > move(global_addr[i]^, Keep_ShareDllPtr^[j],global_Size[i]);

    > // <--- Keep_ShareDllPtr의 내용에 저장하려고 합니다.

    > j := j + global_Size[i];

    > end;

    >

    > end;

    >

    > procedure SV_GET; StdCall;

    > var

    > i, j : integer;

    > Dest_Chr : ARRAY_CHAR;

    > begin

    > j := 1;

    > for i := 1 to ( global_num ) do

    > begin

    > move(Keep_ShareDllPtr^[j], global_addr[i]^, global_size[i]);

    > // <--- Keep_ShareDllPtr의 내용을 가지고 오려고 하는 것입니다.

    > j := j + global_size[i];

    > end;

    > end;

    >

    > procedure AddPointer( Ptr : P_REAL; Size : Integer ); StdCall;

    > begin

    > inc(global_num);

    > global_addr[global_num] := ptr;

    > global_size[global_num] := 4 * Size;

    > end;

    >

    > procedure KeepGlobalPointer( Ptr : PARRAY_CHAR); StdCall;

    > begin

    > Keep_ShareDllPtr := Ptr; //<--- Keep_ShareDllPtr이라는 전역변수에 값을 저장하고 싶은것것입니다.

    > end;

    >

    > procedure OpenSharedData;

    > var

    > i : integer;

    > begin

    >

    > global_num := 0;

    >

    > for i := 1 to 10000 do begin

    > global_size[i] := 0;

    > end;

    >

    > end;

    >

    > procedure CloseSharedData;

    > begin

    > end;

    >

    > procedure DLLEntryPoint(dwReason: DWord);

    > begin

    > case dwReason of

    > DLL_PROCESS_ATTACH: OpenSharedData;

    > DLL_PROCESS_DETACH: CloseSharedData;

    > end;

    > end;

    >

    > exports

    > AddPointer, SV_SET, SV_GET, KeepGlobalPointer;

    >

    > begin

    > { First, assign the procedure to the DLLProc variable }

    > DllProc := @DLLEntryPoint;

    > { Now invoke the procedure to reflect that the DLL is attaching

    > to the process }

    > DLLEntryPoint(DLL_PROCESS_ATTACH);

    > end.