2010-11-22 3 views
2

Я полностью провалил это очень простое P/Invoke.Marshalling простая строка в C#

[System.Runtime.InteropServices.DllImport(
     "temp.dll" 
    )] 
    private static extern System.IntPtr parser_alloc(); 

    [System.Runtime.InteropServices.DllImport(
     "temp.dll", 
     CharSet = System.Runtime.InteropServices.CharSet.Ansi 
    )] 
    private static extern void parser_add_file(
     System.IntPtr p, 
     [MarshalAs(UnmanagedType.LPStr)]string f, 
     [MarshalAs(UnmanagedType.LPStr)]string s); 

    [System.Runtime.InteropServices.DllImport(
     "temp.dll" 
    )] 
    private static extern void parser_free(
     System.IntPtr p); 

    [System.Runtime.InteropServices.DllImport(
     "temp.dll" 
    )] 
    private static extern void parser_emit_results(
     System.IntPtr p); 

    [System.Runtime.InteropServices.DllImport(
     "temp.dll", 
     CharSet = System.Runtime.InteropServices.CharSet.Ansi 
    )] 
    private static extern void parser_file_updated(
     System.IntPtr p, 
     [MarshalAs(UnmanagedType.LPStr)]string f, 
     int offset, 
     int added); 

Создание объекта кажется прекрасным. Однако, когда я пытаюсь вызвать parser_add_file, тогда среда выполнения говорит мне, что у меня есть несогласованная подпись. Это мой существующий C++ код:

class Parser { 
public: 
    void add_file(std::string filename, std::string source) { 
     std::cout << "add_file | " << filename << " | " << source << "\n"; 
    } 
    void clear_contents() { 
     std::cout << "clear_contents\n"; 
    } 
    void emit_results() { 
     std::cout << "emit_results\n"; 
    } 
    void file_updated(std::string filename, int offset, int added) { 
     std::cout << "file_updated | " << filename << " | " << offset << " | " << added << "\n"; 
     // added should be negative to signify removing 
    } 
    Parser() { 
     std::cout << "I made a Parser!\n"; 
    } 
}; 

extern "C" __declspec(dllexport) Parser* parser_alloc() { 
    return new Parser; 
}; 

extern "C" __declspec(dllexport) void parser_add_file(Parser* p, const char* filename, const char* string) { 
    p->add_file(filename, string); 
} 

extern "C" __declspec(dllexport) void parser_free(Parser* p) { 
    delete p; 
} 

extern "C" __declspec(dllexport) void parser_emit_results(Parser* p) { 
    p->emit_results(); 
} 

extern "C" __declspec(dllexport) void parser_file_updated(Parser* p, const char* filename, int offset, int added) { 
    p->file_updated(filename, offset, added); 
} 

Должен ли я просто пропустить P/Invoke и перейти на C++/CLI для этой работы?

ответ

1

Оказывается, мне пришлось вручную установить соглашение о вызове cdecl - по умолчанию используется stdcall.

0

Если у вас есть доступ к источнику C++ (как он выглядит), вы можете изменить соглашение о вызове на уровне декларации C++. Вот пример функции для библиотеки, которую я написал:

int _stdcall GeoConvertLatLongToUTM(double latitude, double longitude, char *szOutput) 
Смежные вопросы