VC++ DLL과 인터페이싱하는데 델파이 고유의 자료형인 동적배열(array of ...)을 사용하니 문제가 생기는 겁니다.
VC코드에 있는것처럼 델파이에서도 정적배열(array[0..최대값] of SmallInt)의 포인터를 사용하세요. VC코드처럼 DLL함수 호출하기 전에 메모리할당하시구요. 다 쓴뒤에도 메모리 해제하시구요.
눈팅이 님이 쓰신 글 :
: 업체에서 dll을받아 VC용샘플을 델파이로 변경하여 진행하고있는데 알 수없는 런타임 에러가 발생하고있어 헤메고있습니다.
: 아무래도 메모리상에서 뭔가 꼬이면서 발생하는것 같은데 해결법을 모르겠습니다.. ㅠㅠ
:
: DioSTT_Edu_ENG_Get_Score 라는 함수를 실행하고나면 문제가 발생하는데.. 요것이 하는일이 RECOGNITION_RESULT_ENG구조체를 레퍼런스 파리미터로받아
: 해당구조체에 값을 채워주는식입니다. 그냥 해당함수만 실행시키고나면 별 문제없는데.. 해당함수실행뒤 채워진값을가지고 뭔가를 하면 그때부터 문제가 생겨버립니다.
: (구조체안에 데이터는 정상적으로 들어와있습니다.)
:
: 짐작되는 부분은 구조체내의 EPD_Buf넘이 smallint형 동적배열인데 요넘에게 Dll함수가 배열원소들을 채워서주게되고나서
: 델파이에서 구조체의 끝점을 찾지못해 발생하는 문제가 아닌가 짐작됩니다...
:
: 아무래도 레코드부분 선언을 제가 잘못한것같은데 뭔지를 모르겠습니다. 업체에도 물어 볼 수도 없는것이.. 업체는 델파이가 뭔지도 모르고 있습니다.ㅡ.ㅡ;;
:
: ※참고로 제가 VC++로 임의Dll을 만들어서 해당 구조체를 가지고 EPD_Buf에 값을 넣어서 리턴 해 보았는데 제가 임의로 만들어서 테스트 해본넘은 문제가 없었습니다..
: 하지만 제 테스트용 과 업체측 제공 dll에서의 EPD_Buf에 데이터를 넣어주는 방식이 틀린지 디버깅걸어보면 업체측Dll에서는 [0]42,[1]35,[2]55.. 이런식인데
: 제 테스트용 dll에서 넣어준 데이터는 실제 디버깅에서는 찾지는못하고 찍어보면 값이 정상적으로 나옵니다.
:
: **** VC 코드
:
: #ifdef WIN32
: #define __decls_dllexport__ __declspec(dllexport)
: #ifdef __cplusplus
: #define DIOSTT_EDU_ENG_API extern "C" __declspec(dllexport)
: #else
: #define DIOSTT_EDU_ENG_API __declspec(dllexport)
: #endif
:
: #define L_ENG_MAX_LIST_CNT (4096-1) // 최대 리스트 수
: #define L_ENG_MAX_LIST_LEN 128 // 리스트 하나의 최대 길이
: #define L_ENG_MAX_WORD_LEN 32 // 한 단어의 최대 길이
: #define L_ENG_MAX_WORD_CNT 128 // 한 문장내 단어의 최대 수
: #define L_ENG_MAX_RESULT_CNT 10
:
: typedef struct RECOGNITION_RESULT_ENG
: {
: int nInputLevel;
: int nInputProfile;
: int nInputPauseThreshold;
: int iTextForm;
: char szInputText[L_ENG_MAX_LIST_CNT*L_ENG_MAX_LIST_LEN];
: int result_cnt;
: char result_string[L_ENG_MAX_RESULT_CNT][L_ENG_MAX_LIST_LEN];
: int result_score[L_ENG_MAX_RESULT_CNT];
: int total_score;
: int word_cnt;
: char word[L_ENG_MAX_WORD_CNT][L_ENG_MAX_WORD_LEN];
: int word_score[L_ENG_MAX_WORD_CNT];
: int word_position[L_ENG_MAX_WORD_CNT][2];
: char phoneme_in_word[L_ENG_MAX_WORD_CNT][L_ENG_MAX_WORD_LEN];
: char phoneme_cnt_in_word[L_ENG_MAX_WORD_CNT];
: int phoneme_score_in_word[L_ENG_MAX_WORD_CNT][L_ENG_MAX_WORD_LEN];
: int phoneme_position_in_word[L_ENG_MAX_WORD_CNT][L_ENG_MAX_WORD_LEN];
: int word_stress[L_ENG_MAX_WORD_CNT];
: unsigned char bEPD; // 1: EPD_OK, 0: EPD_FAIL
: int EPD_position[2];
: int wpm;
: char nSNR;
: int EPD_sample_cnt;
: short* EPD_Buf;
:
: #ifdef __cplusplus
: __decls_dllexport__ RECOGNITION_RESULT_ENG();
: __decls_dllexport__ ~RECOGNITION_RESULT_ENG();
: __decls_dllexport__ void setEPDBuffer(short *buff, int sampleCount);
: __decls_dllexport__ void clearEPDBuffer();
: #endif
:
: }Recognition_Result_ENG;
:
: DIOSTT_EDU_ENG_API int DioSTT_Edu_ENG_Get_Score(Recognition_Result_ENG *pScore);
:
:
:
: **** 델파이 2010 코드
: const
: L_ENG_MAX_LIST_CNT = (4096 - 1);
: L_ENG_MAX_LIST_LEN = 128;
: L_ENG_MAX_WORD_LEN = 32;
: L_ENG_MAX_WORD_CNT = 128;
: L_ENG_MAX_RESULT_CNT = 10;
:
: type
: TEpdBuf = array of SmallInt;
: PEpdBuf = ^TEpdBuf;
:
: PRecognition_Result_ENG = ^TRecognition_Result_ENG;
: TRecognition_Result_ENG = record
: nInputLevel: integer;
: nInputProfile: integer;
: nInputPauseThreshold: integer;
: iTextForm: integer;
: szInputText: array [0..L_ENG_MAX_LIST_CNT * L_ENG_MAX_LIST_LEN - 1] of ansichar;
: result_cnt: integer;
: result_string: array [0..L_ENG_MAX_RESULT_CNT - 1, 0..L_ENG_MAX_LIST_LEN - 1] of ansichar;
: result_score: array [0..L_ENG_MAX_RESULT_CNT - 1] of integer;
: total_score: integer;
: word_cnt: integer;
: word: array [0..L_ENG_MAX_WORD_CNT - 1, 0..L_ENG_MAX_WORD_LEN - 1] of ansichar;
: word_score: array [0..L_ENG_MAX_WORD_CNT - 1] of integer;
: word_position: array [0..L_ENG_MAX_WORD_CNT - 1, 0..1] of integer;
: phoneme_in_word: array [0..L_ENG_MAX_WORD_CNT - 1, 0..L_ENG_MAX_WORD_LEN - 1] of ansichar;
: phoneme_cnt_in_word: array [0..L_ENG_MAX_WORD_CNT - 1] of ansichar;
: phoneme_score_in_word: array [0..L_ENG_MAX_WORD_CNT - 1, 0..L_ENG_MAX_WORD_LEN - 1] of integer;
: phoneme_position_in_word: array [0..L_ENG_MAX_WORD_CNT - 1, 0..L_ENG_MAX_WORD_LEN - 1] of integer;
: word_stress: array [0..L_ENG_MAX_WORD_CNT - 1] of integer;
: bEPD: byte;
: EPD_position: array [0..1] of integer;
: wpm: integer;
: nSNR: ansichar;
: EPD_sample_cnt: integer;
: EPD_Buf: TEpdBuf; // <--동적 배열입니다.
: //EPD_Buf: PEpdBuf;
: //EPD_Buf: PSmallInt;
: end;
:
:
: function DioSTT_Edu_ENG_Get_Score(var UserResult: TRecognition_Result_ENG): integer; stdcall; external 'DioSTT_Edu_ENG.dll';
: //function DioSTT_Edu_ENG_Get_Score(pUserResult: PRecognition_Result_ENG): integer; stdcall; external 'DioSTT_Edu_ENG.dll';
:
:
: **** 델파이 2010 실행코드
: procedure TFormMain.ENG_GetScore;
: var
: uRet: TRecognition_Result_ENG;
: fs: TFileStream;
: begin
: uRet.EPD_Buf := nil;
: DioSTT_Edu_ENG_Get_Score(uRet); //요기까지만 실행하면 문제없습니다.
:
: //Memo1.Lines.Add('dd'); //<<-- 하다못해 메모에다 아무메세지만찍어도 런타임 에러가 납니다.
:
: if FileExists(FEPDFile) then
: fs := TFileStream.Create(FEPDFile, fmOpenReadWrite or fmShareDenyNone)
: else
: fs :=TFileStream.Create(FEPDFile, fmCreate);
:
: try
: fs.Position := 0;
: fs.WriteBuffer(uRet.EPD_Buf[0], uRet.EPD_sample_cnt * 2); // <-- EPD_Buf의 값은 정상적으로 들어와서 파일저장까지된 후 런타임 에러가 납니다.
: finally
: fs.Free;
: end;
:
: end;
:
:
: **** 임의 테스트용 Dll코드와 델파이코드
: - dll 코드
: extern "C" __declspec(dllexport)
: int TestApi(Recognition_Result_ENG *pScore) {
:
: pScore->nInputLevel = 10;
: pScore->nInputProfile = 15;
: pScore->nInputPauseThreshold = 25;
: pScore->iTextForm = 35;
: strcpy(pScore->szInputText, "babo");
: pScore->EPD_sample_cnt = 23454;
:
: pScore->EPD_Buf = (short *)malloc(sizeof(short) * 23454);
: for (short i = 0; i < pScore->EPD_sample_cnt; i++) {
: pScore->EPD_Buf[i] = i;
: }
:
: return 1;
: }
:
:
: - 델파이코드
: function TestApi(var UserResult: TRecognition_Result_ENG): integer; stdcall; external 'testdll.dll';
: procedure TFormMain.Button1Click(Sender: TObject);
: var
: i, nResult: integer;
: uRet: TRecognition_Result_ENG;
: begin
: uRet.EPD_Buf := nil;
: nResult := TestApi(uRet);
:
: Memo1.Lines.Add(IntToStr(nResult));
: Memo1.Lines.Add(IntToStr(uRet.nInputLevel));
: Memo1.Lines.Add(IntToStr(uRet.nInputProfile));
: Memo1.Lines.Add(IntToStr(uRet.nInputPauseThreshold));
: Memo1.Lines.Add(IntToStr(uRet.iTextForm));
: Memo1.Lines.Add(uRet.szInputText);
: Memo1.Lines.Add(IntToStr(uRet.EPD_sample_cnt));
: for i:=0 to 23453 do begin
: Memo1.Lines.Add(IntToStr(uRet.EPD_Buf[i]));
: end;
:
: end;
:
|