알 수있는 문자를 받아들이는 관리되지 않는 메서드를 호출 할 때 * C에서 # 인수, 모두 StringBuilder를 전달하고 관리되지 않는 C 코드를 수정하는 것이 가능하다 . 그러나 StringBuilder에 넣으려는 데이터의 크기를 알아야하므로 올바른 크기의 버퍼를 전달할 수 있습니다. 나는 이것을 도와주는 많은 스레드를 발견했다.** 관리 C# 코드에서 인수
그러나 char ** 인수를 허용하는 C 메서드가 있습니다.
이것은 (아래) check_if_encrypted
같은 방법 check_if_encrypted
에서 다음과 같은 코드를 사용하여 오류 메시지 버퍼에 할당하는 공간이 얼마나되는지 알 필요 호출 방법없이 malloc
'D 에러 메시지를 제공 할 수 : *strTheCharStarStarArgument = strLocalMallocdErrorMessage
을 그리고를 통해 호출 할 때 &strErrorMessage
strErrorMessage
은 char*
입니다. C#에서 이러한 메서드에 어떤 DLLImport 서명을 사용해야합니까?
는 예를 들어, 나는 다음과 같은 C 코드를 한 :
헤더 :
extern __declspec(dllexport) KeyFile *create_source_key_file_from_path(char *strPath);
extern __declspec(dllexport) int check_if_encrypted(KeyFile *kfSourceKey, int ktSourceKeyType, const char **strErrorMessage);
홈페이지 코드 :
KeyFile *create_source_key_file_from_path(char *strPath) {
/* Snip */
}
int check_if_encrypted(KeyFile *kfSourceKey, int ktSourceKeyType, const char **strErrorMessage) {
/* Snip */
char* strLocalErrorMessage = (char*)malloc(sizeof(char)*17);
strcpy(strLocalErrorMessage,"This is an error");
*strErrorMessage = strLocalErrorMessage;
/* Snip */
}
/* Snip */
int main(int argc, char *argv[]) {
KeyFile *kfSource;
char *strErrorMessage;
const char **strErrorMessageP = &strErrorMessage;
int intIsEncrypted;
kfSource = create_source_key_file_from_path("test.dat");
intIsEncrypted = check_if_encrypted(kfSource,0,strErrorMessageP);
if (strErrorMessage != NULL) {
/* Handle error here. */
}
else if (intIsEncrypted == 1) {
/* Handle encrypted file here. */
}
else {
/* Handle unencrypted file here. */
}
}
사용하여 C#으로이 주요 방법을 복제하려고 시도한은 check_if_encrypted 방법 관리되지 않는 메서드로 인해 check_if_encrypted를 호출 할 때 AccessViolationException (보호 된 메모리를 읽거나 쓰려고 시도 함)이 발생했습니다.
[DllImport("PPKConverter.exe", SetLastError = true, CallingConvention = CallingConvention.Cdecl, CharSet=CharSet.Ansi)]
public extern static IntPtr create_source_key_file_from_path([MarshalAs(UnmanagedType.LPStr)] StringBuilder strPath);
[DllImport("PPKConverter.exe", SetLastError = true, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public extern static int check_if_encrypted(IntPtr kfSourceKey, int ktSourceKeyType, [MarshalAs(UnmanagedType.LPStr)] ref StringBuilder sbErrorMessage);
[STAThread]
public static void Main(String[] args)
{
StringBuilder sbPath = new StringBuilder(@"test.dat");
StringBuilder sbErrorMessage = new StringBuilder();
IntPtr ipKeyFile = create_source_key_file_from_path(sbPath); // This works
int intIsEncrypted = check_if_encrypted(ipKeyFile, 0, ref sbErrorMessage); // This throws the exception.
/* Snip */
}
나는이 잘못되는 같이 DllImport 서명에 ref StringBuilder
의 내 사용으로 인해 생각합니다. 대신 무엇을 사용해야합니까?
감사 호출자에게 비 관리 코드 반환 malloc
의 호출에 할당되는
답변 해 주셔서 감사합니다. 당신이 언급 한 P/Invoke 선언을 변경하고, IntPtr.Zero로 초기화 된 IntPtr에 대한 참조를 전달하는 것을 확인할 수 있습니다. 실제로 EXE에 연결하는 것이 아니라 잘못된 파일 확장명을 가진 DLL을 연결하는 중입니다. 나는 원래 exe를 사용하려고했지만 작동하지 않았고, 아직 이름을 다시 변경하지 않았습니다. malloc없이 알 수없는 크기의 문자열을 되돌려 보내는 방법이 있습니까? 또한 deallocator를 내보내서 무료라는 다른 DLL 함수를 의미합니까? –
매개 변수가 의미 론적으로 벗어 났으므로 지금은 ref에서 out으로 변경했습니다. 그런 다음 초기화 할 필요가 없습니다. 내 실수. –
deallocator를 내 보냅니다. 예, 포인터를 받아들이고 그것을 자유롭게 전달하는 함수를 내 보냅니다. –