Я создаю приложение .NET для вызова неуправляемой DLL (Юникод).
Ниже приведен заголовок неуправляемой DLL:
#pragma once
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
// Callback function for ProcessFileAPI. The function is called whenever progress advances.
typedef VOID (CALLBACK* LPPROGRESSPROC)(CONST BYTE btProgress, LPVOID lParam);
#pragma pack(1)
// Options for ProcessFileAPI
typedef struct _OPTIONS1
{
BOOL m_bOption1;
BOOL m_bOption2;
} OPTIONS1, *LPOPTIONS1;
#pragma pack()
DWORD WINAPI ProcessFileAPI(LPCTSTR lpSrcFileName, LPCTSTR lpDstFileName, LPPROGRESSPROC lpProgressProc, LPVOID lpProgProcParam,
LPBOOL pbCancel, CONST LPOPTIONS1 lpOptions1);
#ifdef __cplusplus
}
#endif
И .cpp для неуправляемой DLL:
extern "C" DWORD WINAPI ProcessFileAPI(LPCTSTR lpSrcFileName, LPCTSTR lpDstFileName, LPPROGRESSPROC lpProgressProc, LPVOID lpProgProcParam,
LPBOOL pbCancel, CONST LPOPTIONS1 lpOptions1)
{
TRACE(_T("SrcFileName: %s. DstFileName: %s."), lpSrcFileName, lpDstFileName);
return 0;
}
Ниже приведен код .NET для этой функции:
using System;
using System.Runtime.InteropServices;
namespace SDKAPI
{
public struct TOptions1
{
public bool bOption1;
public bool bOption2;
} // end TOptions1
public delegate void TProgressProc(byte btProgress, IntPtr lParam);
}
namespace SDKAPI.Units
{
public class SDKAPI
{
[DllImport("SDK.DLL")]
public static extern uint ProcessFileAPI(string lpSrcFileName, string lpDstFileName, TProgressProc pgrsproc, IntPtr lpProgProcParam, ref int pbCancel, ref TOptions1 options);
} // end SDKAPI
}
А ниже вызов функции:
Options1.bOption1 = true;
Options1.bOption2 = false;
// Process the file
FCancel = 0;
RetCode = SDKAPI.Units.SDKAPI.ProcessFileAPI(txtSrcFile.Text, txtDstFile.Text, new SDKAPI.TProgressProc(this.ProgressProc), IntPtr.Zero, ref FCancel, ref Options1);
При вызове DLL с помощью txtSrcFile.Text = "a"
и txtDstFile.Text = "b"
, но я отлаживаю DLL и обнаруживаю, что параметр lpSrcFileName
становится "a"
, за которым следует множество странных символов. Почему?
@ChrisMM LPCTSTR
тоже не LPWStr
.
@alancc Вы скомпилировали dll как Unicode или нет? Добавьте эту информацию в свой [DllImport]
, используя свойство CharSet.
@GSerg, DLL находится в Юникоде.
Затем используйте CharSet.Unicode в объявлении функции. Если он отсутствует, он принимает 8-битные символы, и строка преобразуется в китайский язык.
Вам необходимо выяснить, использует ли неуправляемая DLL Unicode или нет. Если да, то нужно CharSet.Unicode
иначе CharSet.Ansi
.
Также необходимо установить пак.
[StructLayout(LayoutKind.Sequential, Pack=1)]
public struct TOptions1
{
public bool bOption1;
public bool bOption2;
}
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
public delegate void TProgressProc(byte btProgress, IntPtr lParam);
[DllImport("SDK.DLL", CharSet = CharSet.Unicode)]
public static extern uint ProcessFileAPI(
string lpSrcFileName, string lpDstFileName, TProgressProc pgrsproc,
IntPtr lpProgProcParam, ref bool pbCancel, [In] in TOptions1 options);
bool
, — это I4, а не I1. Для этого есть UnmanagedType.Bool
, который в любом случае является значением по умолчанию.
ОК, исправил это. Меня всегда смущают эти двое.
DLL находится в Unicode, я обновил свой вопрос.
Несколько вопросов: 1. Поскольку BOOL отличается от bool, почему в кодах все еще используется bool? 2. «[In] в параметрах TOptions1» вызовет ошибку компилятора, поэтому я заменяю его на «[In] TOptions1 options», но передаваемые значения всегда неверны.
bool
в C# есть только один тип. Вопрос был только в том, на что это сопоставить при маршаллинге. Какую ошибку компилятора вы получаете? Отлично работает в .NET 8 dotnetfiddle.net/KMe2Px Если вы используете .NET Framework, измените его обратно на ref
. Не используйте его без ref
или in
, иначе это не сработает.
Я использую C# в Visual Studio 2008, и компилятор видит «C:\Windows\Microsoft.NET\Framework\v3.5». Так что я думаю, что это .net framework.
Я предполагаю, что вы понимаете, что поддержка VS 2008 прекратилась в 2018 году, и что в .NET 3.5, хотя она все еще поддерживается, отсутствуют многие исправления и улучшения производительности и удобства использования, поэтому я настоятельно рекомендую вам обновиться как можно скорее. В будущем обязательно отмечайте .net-3.5, потому что люди не поймут.
Я понимаю. Я добавил тег .net-3.5. Также могу ли я использовать uint в качестве типа для C++ BOOL? Поскольку uint в C# имеет размер 4 байта, что в точности соответствует C++ BOOL.
Да, ты можешь, если хочешь
Обычно я использую управляемый уровень C++/CLI, но C#
string
— это не то же самое, чтоLPCTSTR
. В объявленииextern
на C# попробуйте добавить[MarshalAs(UnmanagedType.LPWStr)]
передstring lpSrcFileName
. По умолчанию —BStr
, см. здесь