저는 C++ 응용 프로그램 용 C# GUI를 작성하고 있습니다. 사용 가능한 DLL을 열거하고, 하나씩 동적으로로드하고, 문자열에 연결된 플러그인 설명을 반환하는 "getdescstring"이라는 함수를 호출하여 플러그인의 세부 정보를 검색합니다.C++ DLL에서 모노 (C#)로 메모리 손상 전달 문자열
이것은 Windows에서 완벽하게 작동합니다. 그러나 리눅스에서 실행하려고 할 때 (Linux Mint 64 비트 (Mono 3.0.6) 및 Xubuntu 32 비트 (Mon 2.10.8) 가상 머신에서 시도한 경우, g ++ - 4.7 on 둘 다) 반환 된 문자열의 대부분은 다음과 같이 손상되었습니다.
"grown|Barabasi-Albert grown network.|1,000|1.0|1.0|1.0||n|Number of nodes|numeric|k|Degree of neA\0\0…"
독립형 C++ 테스트 프로그램에서 함수를 호출하면 작동합니다. Valgrind에 메모리 누출이나 손상이 없습니다. Valgrind를 통해 Mono로 전체 프로그램을 실행하려고하면 초기화시 충돌이 발생하므로보고 할 수 없습니다.
그래서 Mono와 DLL 사이의 메모리 손상이 의심 스럽지만 위치를 식별 할 수 없습니다.
업데이트 : 내 직관은 어떻게 든 호출 규칙이 혼재하는 것입니다. 64 비트 프로그램에는 고유 한 호출 규칙이 있기 때문에 Mono는 ms_abi를 사용합니다. 이는 UNIX의 sysv_abi와 충돌 할 수 있습니다. 그러나 이것들에 대한 호출 규칙 플래그가 없으므로 문제가 있더라도 해결할 수는 없습니다. CC를 Mono에서 stdcall로 설정할 수 있지만 g ++은 64 비트 CPU에서 CC 속성을 무시합니다. 아니요. 32 비트 가상 컴퓨터에서 양쪽 끝을 stdcall로 설정하려고 시도했지만 변경하지 않았습니다.
다음은 DLL에서 호출 된 코드입니다 (함수 "description"은 std :: vector를 반환 함). 문자열,하지만 C 번호에 직접 표준 : : 벡터 전달은 매우 불쾌한 듯)
extern "C" const char* getdescstring()
{
vector<vector<string> > descvec=description();
string descstr;
for(unsigned i=0;i<descvec.size();i++)
{
for(unsigned j=0;j<descvec[i].size();j++)
{
descstr+=descvec[i][j];
descstr+="|";
}
descstr+="|";
}
return descstr.c_str();
}
그리고이 지정된 문자열을 다시 변환 수신 기능입니다 : 나는 또한이 방법을 시도
public static List<List<string>> GetPluginDesc(string plugin)
{
List<List<string>> des = new List<List<string>>();
DllLoadUtils dl;
if (OS == platform.Windows) dl = new DllLoadUtilsWindows();
else dl = new DllLoadUtilsLinux();
IntPtr dllh = dl.LoadLibrary(plugin);
if (dllh == IntPtr.Zero) return null;
IntPtr proc = dl.GetProcAddress(dllh, "getdescstring");
if (proc == IntPtr.Zero) return null;
dsc descr = (dsc)Marshal.GetDelegateForFunctionPointer(proc, typeof(dsc));
String descstr = Marshal.PtrToStringAnsi(descr());
string[] descelem = descstr.Split('|');
List<string> ls = new List<string>();
foreach (string s in descelem)
{
//double pipe means EOL
if (s == "") { des.Add(ls); ls = new List<string>(); }
else ls.Add(s);
}
if (ls.Count > 0) des.Add(ls);
dl.FreeLibrary(dllh);
return des;
}
을 (델리게이트 수정하기 그리고, 어떤 합리적인 데이터가 전송되지 된 DLL에서 함수는 문자 * 및 매개 변수로 길이)에 동의합니다,하지만 결과는 더 악화했다 :
dsc descr = (dsc)Marshal.GetDelegateForFunctionPointer (proc, typeof(dsc));
IntPtr sf = Marshal.AllocHGlobal(1024);
descr (sf,1024);
String descstr = Marshal.PtrToStringAnsi(sf);
Marshal.FreeHGlobal(sf);
난 어떤 도움을 주셔서 감사합니다. 미리 감사드립니다.
interface DllLoadUtils {
IntPtr LoadLibrary(string fileName);
void FreeLibrary(IntPtr handle);
IntPtr GetProcAddress(IntPtr dllHandle, string name);
}
public class DllLoadUtilsWindows : DllLoadUtils {
void DllLoadUtils.FreeLibrary(IntPtr handle) {
FreeLibrary(handle);
}
IntPtr DllLoadUtils.GetProcAddress(IntPtr dllHandle, string name) {
return GetProcAddress(dllHandle, name);
}
IntPtr DllLoadUtils.LoadLibrary(string fileName) {
return LoadLibrary(fileName);
}
[DllImport("kernel32")]
private static extern IntPtr LoadLibrary(string fileName);
[DllImport("kernel32.dll")]
private static extern int FreeLibrary(IntPtr handle);
[DllImport("kernel32.dll")]
private static extern IntPtr GetProcAddress (IntPtr handle, string procedureName);
}
internal class DllLoadUtilsLinux : DllLoadUtils {
public IntPtr LoadLibrary(string fileName) {
return dlopen(fileName, RTLD_NOW);
}
public void FreeLibrary(IntPtr handle) {
dlclose(handle);
}
public IntPtr GetProcAddress(IntPtr dllHandle, string name) {
// clear previous errors if any
dlerror();
var res = dlsym(dllHandle, name);
var errPtr = dlerror();
if (errPtr != IntPtr.Zero) {
MessageBox.Show("dlsym: " + Marshal.PtrToStringAnsi(errPtr));
}
return res;
}
const int RTLD_NOW = 2;
[DllImport("libdl.so")]
private static extern IntPtr dlopen(String fileName, int flags);
[DllImport("libdl.so")]
private static extern IntPtr dlsym(IntPtr handle, String symbol);
[DllImport("libdl.so")]
private static extern int dlclose(IntPtr handle);
[DllImport("libdl.so")]
private static extern IntPtr dlerror();
}
를 대리자가 단순히 : 다음에 선언 당신은 descstr.c_str()
을 반환하는
public delegate IntPtr dsc();
입력 해 주셔서 감사합니다. 다음 코드를 작성했습니다 : 나는 그것이 못 생겼다는 것을 알고 있으며, 빨리 시도하고 싶습니다. 'char desc [2000]; extern "C"const char * getdescstring() { \t 벡터 <벡터> descvec = 설명(); \t 문자열 descstr; 위한 \t (부호 I = 0; I)는 (descvec.size를 <; 내가 ++) 용 \t { \t \t (부호 J = 0; J
'strncpy'는 문자열을 종료하지 않습니다. 사용하기 전에'memset'ting을 바이너리 0으로 시도하거나 그렇지 않으면 바이너리 0을 복사 된 문자열의 끝에 추가하십시오. – edtheprogrammerguy
이것이 문제라면 끝 부분에 많은 쓰레기가있는 문자열 자체를 완전히 보았어야 했습니까? 그러나 쓰레기가 아닌 경우 반으로 줄입니다. 나는 그것을 시도했지만 결과는 같았다. –