本文接上篇文章 C#獲取設備(Audio和Video)名稱 簡單整理,對第四種方式使用整理.
EnumDevice.dll是網上下載的,也下載了對應的源代碼,
對應dll:https://download.csdn.net/download/QQ81867376/12322158
該dll的源碼: https://download.csdn.net/download/QQ81867376/12322152
由於項目剛好是x86,所以直接使用上面下載的dll,暫未去編譯源代碼。
C# 調用EnumDevice.dll的方法時候遇到不少問題,在此記錄下。
查看C++函數信息,可以使用工具dllExportViewer
下載地址:http://www.nirsoft.net/utils/dll_export_viewer.html
該dll的原型
__declspec(dllimport)EnumDevice(CAPTURE_DEVICE_TYPE type, char * deviceList[], int nListLen, int & iNumCapDevices);
由於未在前面添加extern "C" 一直找不到該方法,暫時使用了索引來進行。
如果函數過多且經常變化使用索引不恰當 ,但這里只有一個方法,因此無礙,就直接使用索引。
C#方法聲明 這里耽誤點時間,開始僅僅以為按照類型對上即可,定義了如下方法:
//LPStr、LPWStr、BStr 或 LPTStr
[DllImport(EnumDeviceDll, EntryPoint = "#1", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public extern static int EnumDevice(CAPTURE_DEVICE_TYPE type,
[In, Out, MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStr)] string[] deviceList,
int nListLen, ref int iNumCapDevices);
public static List<string> GetDeviceList()
{
var list = new string[10];
int index = 0;
int result = EnumDevice(CAPTURE_DEVICE_TYPE.DSHOW_AUDIO_DEVICE, list, list.Length, ref index);
List<string> listAudio = null;
if (result == 0)
{
listAudio = new List<string>();
foreach (var item in list)
{
if (string.IsNullOrEmpty(item))
{
continue;
}
listAudio.Add(item);
}
}
return listAudio;
}
一運行就報錯:其他信息: 嘗試讀取或寫入受保護的內存。這通常指示其他內存已損壞 .
無奈 就查看源代碼,發現每一項沒有指定大小.就添加了代碼
for (int i = 0; i < list.Length; i++)
{
list[i] = new string(new char[256]);
}
運行果然沒有報錯,
可是有亂碼和用ffmpeg調用指令 (ffmpeg -list_devices true -f dshow -i dummy) 輸出的結果一樣亂碼.
於是各種轉碼無效, 各種定義函數 CharSet = CharSet.Ansi,
ArraySubType = UnmanagedType.LPStr //LPStr、LPWStr、BStr 或 LPTStr 。
試了個遍全都無效,無奈只能換思路了。
修改對應類型,C++里面的 char*,正常直接可以用C#里面string或者char *,
之前使用C#調用FFMpeg的API播放rtmp協議的視頻和語音的時候 好像使用過,看了下之前代碼,重新定義了接口
[DllImport(EnumDeviceDll, EntryPoint = "#1", CallingConvention = CallingConvention.Cdecl)]
public extern static int EnumDevice(CAPTURE_DEVICE_TYPE type,
[In, Out, MarshalAs(UnmanagedType.LPArray)] IntPtr[] deviceList,
int nListLen, ref int iNumCapDevices);
調用賦值
var list = new IntPtr[10];
int index = 0;
for (int i = 0; i < list.Length; i++)
{
list[i] = Marshal.AllocHGlobal(256);
}
直接給每一項分配內存,Marshal.AllocHGlobal(256)
結果是 無法或者到底有多個設備列表, 除了正常外 其他全是亂碼,
后來就用字符串來代替,
var stringEmpty = new string(new char[256]);
list[i] = Marshal.StringToHGlobalAnsi(stringEmpty);
終於一切都正常了,C#調用一個vc++的函數,就耽誤個把小時。
