1. 위의 클래스를 생성하는 함수
Function CreateCommLib(ParentHandle : integer) : Pointer;
begin
....
ParentHandle 는 정보를 받을 윈도우겠고
리턴값은 인스턴스의 포인터 이겠죠(멀티포트 같은것 쓰기 위해서
인스턴스가 여러개일 수 있다는 것을 가정한것입니다.)
end;
2. 클래스의 셋업정보 보내줘야 겠죠
Function SetupCommLib(CommObject : Pointer; Setup : SetupType) : integer;
begin
....
CommObject 해당 인스턴스의 포인터
SetUp 은 포트 몇번, 속도 몇 등등...
리턴값은 알아서 즉, 오픈되어있는 다시 셋업한다 했을때 에러 몇번등등
end;
3. 클래스내의 Comm Object를 Open
4. 클래스내의 Comm Object를 Close
5. 1에서 생성했으니 다시 인스턴스를 없애야 겠죠
6. Comm의 내용을 Read
7. Comm에 내용을 Write
8. Comm의 버퍼 클리어 등....
이상 위의것은 1~5는 기본적으로 DLL에 있어야 겠고
6~8은 알아서..
클래스 에 있을것은
당연히 Comm 컴퍼넌트가 있어야 겠고
버퍼(큐)를 관리하는 루틴
패킷 데이타 다 받았으니 큐에 있는 데이타 긁어가라고 하는 메세지 부분
전송부 ex SendMessage(ParentHandle, WM_READCOMMDATA,
인스턴스의 포인터 정보...);
요약을 잘 해주시고 친절히 답변해 주신점 깊이 감사드립니다.
그러나 너무 모르는 터라 예제가 있었으면 좋겠다 생각 하여 부탁 드리고 싶었지만 노력도 하지 않는다고 질책 당할까 두려워(^^) 그러진 못하고 다른 방법(Data Module을 이용한)으로 접근한게 있습니다.
DLL만들어서 테스트를 그런데로 하고 있습니다.^^;
그런데 문제가 생기는 부분이 있는데 시간 되시면 소스좀 검토해 주시기 바랍니다.
※ 문제점 설명
RS232C로 데이터가 수신 될때마다 DataModule에 포함시킨 통신컴포넌트의 RX 이벤트를 이용하여 DLL의 전역변수(strRecv: String;)에 다시 저장하고 외부에서 읽으면 다시 클리어 하는 방식을 사용하였습니다.
그런데 여기서 문제가 발생하였습니다. 데이터가 가끔가다가 사라지고 말아요!
누가 훔쳐가는지 도둑놈을 잡아야 하는데 아무리 소스를 들여다 봐도 잘 모르겠습니다.
DLL의 Function ComPort_ReadStr():PChar; 의 Return되는 Type을 String으로 하고 Sharemem을 Uses에 포함시키면 (호출하는 프로그램에서도 포함) 100% 데이터가 완벽히 올라옵니다.
이렇게 하게되면 BORLNDMM.DLL 이 파일도 배포를 해야 한다기에 PChar형으로 구현 하고 싶습니다.
PChar 타입을 사용하여도 데이터가 올라올때는 잃어버리지 않고 올라 올때도 있는걸로 봐서는 데이타 형이 완전히 틀린것 같지도 않은것 같습니다.
그냥 제 생각에요!
※ 문제가 되는 프로그램 간추린 부분
*****************************************
************ DLL 부분 ********************
*****************************************
Function ComPort_ReadStr():PChar;stdcall;
begin
Result:= DM_Com.ComPort_ReadStr();
end;
*****************************************
******** DataModule의 Unit부분 ***********
*****************************************
public
strRecv: String; //RS232C용 컴포넌트에서 수신된 데이타 저장버퍼
Function ComPort_ReadStr():PChar; //외부에서 수신된 데이터를 폴링방식으로 읽을수 있는 펑션 프로토 타입선언
end;
// 실제 프로그램 되는 부분
Function TDM_Com.ComPort_ReadStr():PChar;
begin
Result:= PChar(StrRecv); //PChar로 형변환
strRecv:= ''; //읽었으니 데이타 수신 버퍼 초기화
end;
// 컴포넌트에서 데이터가 수신될때 발생하는 이벤트 함수
procedure TDM_Com.ComPortRxChar(Sender: TObject; Count: Integer);
var strTemp:string;
begin
ComPort.ReadStr(strTemp,Count);
if (length(strRecv) + Count) >= 512 then // 저장버퍼 제한 512byte
MessageDlg('Receive data overflow error!',mtError,[mbOK],0)
else
begin
strRecv:= strRecv+ strTemp;
end;
end;
DLL 파트쪽은 이게 다입니다.
아래는 호출하는 프로그램입니다.
*********************************************************
******* DLL을 링크하여 읽어보는 테스트 프로그램***********
*********************************************************
var
Form1: TForm1;
Function ComPort_ReadStr():PChar;stdcall;external 'PRJ_Com.dll';
implementation
{$R *.DFM}
// 타이머를 1ms로 폴링하여 수신된 데이터가 있는지 감시함
procedure TForm1.Timer1Timer(Sender: TObject);
var strTemp: String;
begin
strTemp:= ComPort_ReadStr(); //위에 DLL에 있는 수신버퍼 읽는함수
if Length(strTemp) <> 0 then
begin
strReceiveData:= strReceiveData + strTemp;
if (ord(strTemp[Length(strTemp)]) = $FF) then //끝가지 수신
Call Back 함수를 쓰는 방법
Window Message를 쓰는 방법
첫번째 방법은 되긴하는데 전역함수밖에 안되는것 같아서 버렸고요
두번째 방법을 주로 씁니다.
먼저 컴퍼넌트가 있는 클래스 유니트를 구성하셔야 겠고요
디자인(설계라는거 알죠)은 알아서 하셔야 겠고
기본적으로 있어야 하는 부분
DLL Project에 있을것은
1. 위의 클래스를 생성하는 함수
Function CreateCommLib(ParentHandle : integer) : Pointer;
begin
....
ParentHandle 는 정보를 받을 윈도우겠고
리턴값은 인스턴스의 포인터 이겠죠(멀티포트 같은것 쓰기 위해서
인스턴스가 여러개일 수 있다는 것을 가정한것입니다.)
end;
2. 클래스의 셋업정보 보내줘야 겠죠
Function SetupCommLib(CommObject : Pointer; Setup : SetupType) : integer;
begin
....
CommObject 해당 인스턴스의 포인터
SetUp 은 포트 몇번, 속도 몇 등등...
리턴값은 알아서 즉, 오픈되어있는 다시 셋업한다 했을때 에러 몇번등등
end;
3. 클래스내의 Comm Object를 Open
4. 클래스내의 Comm Object를 Close
5. 1에서 생성했으니 다시 인스턴스를 없애야 겠죠
6. Comm의 내용을 Read
7. Comm에 내용을 Write
8. Comm의 버퍼 클리어 등....
이상 위의것은 1~5는 기본적으로 DLL에 있어야 겠고
6~8은 알아서..
클래스 에 있을것은
당연히 Comm 컴퍼넌트가 있어야 겠고
버퍼(큐)를 관리하는 루틴
패킷 데이타 다 받았으니 큐에 있는 데이타 긁어가라고 하는 메세지 부분
전송부 ex SendMessage(ParentHandle, WM_READCOMMDATA,
인스턴스의 포인터 정보...);
실제 만들면 복잡할것 같으나 별로 어렵지 않아요
단순히 컴퍼넌트를 폼에 드래그해서 써 왔다면 어려울수도 있겟지만
저같은 겨우 통신컴퍼넌트 사용시 멀티포트 사용의도를 가졌기에 처음설계부터
클래스 만들고 각각의 별도의 큐를 관리하고등등을 만들어 사용해 왔기에
DLL을 만들때 10분도 안걸리더군요