本文接上篇文章 C#獲取設備(Audio和Video)名稱 簡單整理,對第四種方式使用整理. EnumDevice.dll是網上下載的,也下載了對應的源代碼, 對應dll:https://download.csdn.net/download/QQ81867376/12322158 該dll的源碼: ... ...
本文接上篇文章 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++的函數,就耽誤個把小時。