Прежде всего, извините, что опубликовал такой вопрос, когда так много других было задано по этой теме, но я читал все вопросы, которые смог найти (+ google), и ни один из них не дал мне никаких намеков относительно того, что происходит в моем случае.
У меня есть сторонний .dll (libFLAC) с двумя экспортированными функциями с похожим именем:
FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_file (FLAC__StreamEncoder *encoder, const char *filename, FLAC__StreamEncoderProgressCallback progress_callback, void *client_data)
FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_FILE (FLAC__StreamEncoder *encoder, FILE *file, FLAC__StreamEncoderProgressCallback progress_callback, void *client_data)
Цель первого - инициализировать кодировщик с именем файла. Он вызывает fopen (), что в Windows (с именами файлов Unicode) в некоторых случаях не очень хорошо. Вот почему разработчик предоставляет вторую функцию, которой можно передать открытый FILE * в режиме "w + b" (который я открываю с помощью вызова MSVCRT.DLL _wfopen_s)
Я определил свои объявления P / Invoke следующим образом:
[DllImport(Globals.LIBFLAC_DLL, EntryPoint = "FLAC__stream_encoder_init_file", CharSet = CharSet.Ansi)]
public static extern InitStatus InitFilenameAnsi(IntPtr Encoder, string Filename, ProgressDelegate ProgressCallback, ref Object ClientData);
[DllImport(Globals.LIBFLAC_DLL, EntryPoint = "FLAC__stream_encoder_init_FILE")]
public static extern InitStatus InitFileHandle(IntPtr Encoder, IntPtr FileHandle, ProgressDelegate ProgressCallback, ref Object ClientData);
(странная?) Проблема заключается в том, что вызов функции «file» (строчные буквы) работает отлично, тогда как вызов, который принимает FILE * (IntPtr), не работает (он вызывает исключение AccessViolationException).
Я передаю одни и те же 1-й, 3-й и 4-й параметры обоим, поэтому я почти уверен, что проблема в параметре IntPtr FileHandle (3-й и 4-й значения равны нулю и могут быть равны нулю в соответствии с документацией. тоже не поможет). Я также уверен, что фактический дескриптор файла в порядке: я использую тот же код для _wfopen_s () в другом проекте, и он работает отлично. Файл также создается до сбоя, так что это не проблема.
РЕДАКТИРОВАТЬ: возвращаемое значение является просто открытым перечислением InitStatus: int.
На мгновение я подумал, что может быть проблема с функциями, имеющими почти одинаковые имена, поэтому я попытался вызвать их по порядковому номеру, но это тоже не сработало:
[DllImport(Globals.LIBFLAC_DLL, EntryPoint = "#259", CharSet = CharSet.Ansi)] //"FLAC__stream_encoder_init_file" OK
[DllImport(Globals.LIBFLAC_DLL, EntryPoint = "#258")] //"FLAC__stream_encoder_init_FILE" FAILS
Я также подумал, что, возможно, используемая мной DLL может иметь какую-то проблему, поэтому я переключил ее на версию, скомпилированную другой третьей стороной (размером на 150 КБ), но у меня точно такая же проблема.
Код, который я использую для вызова:
[TestMethod]
public void ThisFailsMiserably()
{
Object ClientData = null;
IntPtr FileHandle = IntPtr.Zero;
try
{
FILE.Open(out FileHandle, "test.flac", "w+b");
Assert.AreNotEqual(IntPtr.Zero, FileHandle); //Works great! the file is created, and the debugger shows the file handle value.
StreamEncoder.InitFileHandle(FlacStreamEncoder, FileHandle, null, ref ClientData); //AccessViolationException
Assert.IsTrue(StreamEncoder.Finish(FlacStreamEncoder));
}
finally
{
FILE.Close(FileHandle);
}
}
[TestMethod]
public void ThisWorksGreat()
{
Object ClientData = null;
Assert.AreEqual(StreamEncoder.InitStatus.OK, StreamEncoder.InitFilenameAnsi(FlacStreamEncoder, "test.flac", null, ref ClientData));
Assert.IsTrue(StreamEncoder.Finish(FlacStreamEncoder));
}
PS: я не знаю, имеет ли это значение, но я использую VS2010 под Win7 x64.
Спасибо, что уделили время заранее