30871 질문 개시물과 연관하여 질문 하는 내용입니다.
질문이 너무 뒷쪽에있어 갱신하고자 다시 올리게 되어 죄송합니다.
이중철 님께서 요약을 잘 해주시고 친절히 답변해 주신점 깊이 감사드립니다.
그러나 너무 모르는 터라 예제가 있었으면 좋겠다 생각 하여 부탁 드리고 싶었지만 노력도 하지 않는다고 질책 당할까 두려워(^^) 그러진 못하고 다른 방법(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 //끝가지 수신
혹시 님 Mobile업체에 근무 하십니까?
소스를 보니 Terminator 문자 $FF 이고
클래스가 DM이라고 적혀있는거 보니 그렇게 유추되네요
제가 그쪽일은 3년간 했거든요 ^^
위의 최용일님께서 하신 말씀이 맞습니다.
그러나 제경우에는 그와는 다른 방법을 쓰고 있거든요
BORLNDMM.DLL 쓰지않고 하는 방법으로서
첫번째는 콜하는 프로그램의 메모리풀을 쓰는 방법이고
두번째는 DLL에서 쓰는 방법인데 제경우 TMemoryStream을 사용해서
해결을 했습니다.
제가 개선해야 할 부문 몇가지 올리겠습니다.
1. Timer는 쓰지 않는 방식을 처리하십시요
(참고로 타이머 1ms 설정한다고 1ms로 작동하지 않습니다)
2. 메모리풀은 512로 한정되어 있는것은 좀 풀어보세요
3. 만약 패킷이 혼합되었을때 처리가 없네요
마지막이 꼭 $FF일 수 없는데
즉, 두패킷이