Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How C++ encapsulates DLL for C# to call

2025-01-31 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

< arguments.Length; i++) { argv.pointers[i] = Marshal.StringToHGlobalAnsi(arguments[i]); } IntPtr argvPtr = IntPtr.Zero; try { int size = Marshal.SizeOf(typeof(PointerToArrayOfPointerHelper)); argvPtr = Marshal.AllocHGlobal(size); Marshal.StructureToPtr(argv, argvPtr, false); return libvlc_new(arguments.Length, argvPtr); } finally { for (int i = 0; i < arguments.Length + 1; i++) { if (argv.pointers[i] != IntPtr.Zero) { Marshal.FreeHGlobal(argv.pointers[i]); } } if (argvPtr != IntPtr.Zero) { Marshal.FreeHGlobal(argvPtr); } } } public static IntPtr libvlc_media_new_path(IntPtr libvlc_instance, string path) { IntPtr pMrl = IntPtr.Zero; try { byte[] bytes = Encoding.UTF8.GetBytes(path); pMrl = Marshal.AllocHGlobal(bytes.Length + 1); Marshal.Copy(bytes, 0, pMrl, bytes.Length); Marshal.WriteByte(pMrl, bytes.Length, 0); return libvlc_media_new_path(libvlc_instance, pMrl); } finally { if (pMrl != IntPtr.Zero) { Marshal.FreeHGlobal(pMrl); } } } public static int libvlc_video_take_snapshot(IntPtr libvlc_mediaplayer, int num, string path, int width, int height) { IntPtr pMrl = IntPtr.Zero; try { byte[] bytes = Encoding.UTF8.GetBytes(path); pMrl = Marshal.AllocHGlobal(bytes.Length + 1); Marshal.Copy(bytes, 0, pMrl, bytes.Length); Marshal.WriteByte(pMrl, bytes.Length, 0); return libvlc_video_take_snapshot(libvlc_mediaplayer, num, pMrl, width, height); } finally { if (pMrl != IntPtr.Zero) { Marshal.FreeHGlobal(pMrl); } } } public static IntPtr libvlc_media_new_location(IntPtr libvlc_instance, string path) { IntPtr pMrl = IntPtr.Zero; try { byte[] bytes = Encoding.UTF8.GetBytes(path); pMrl = Marshal.AllocHGlobal(bytes.Length + 1); Marshal.Copy(bytes, 0, pMrl, bytes.Length); Marshal.WriteByte(pMrl, bytes.Length, 0); return libvlc_media_new_path(libvlc_instance, pMrl); } finally { if (pMrl != IntPtr.Zero) { Marshal.FreeHGlobal(pMrl); } } } #endregion } VLCPlayer public class VLCPlayer { private IntPtr libvlc_instance_; private IntPtr libvlc_media_player_; private double duration_; public VLCPlayer(string pluginPath, bool is_record) { if (is_record == true) { string plugin_arg = "--plugin-path=" + pluginPath; string filename = "c:\\" + DateTime.Now.ToString("yyyyMMddhhmmss") + ".mp4"; string record_paramter = "--sout=#duplicate{dst=display,dst=std{accs=file,mux=ts,dst=" + filename; string[] arguments = { "-I", "--fullscreen", "dummy", "--ignore-config", "--no-video-title", "--width=100", "--height=100", plugin_arg, record_paramter };// "--sout=#duplicate{dst=display,dst=std{accs=file,mux=ts,dst=c:\\1.mp4" }; libvlc_instance_ = LIBVLCAPI.libvlc_new(arguments); libvlc_media_player_ = LIBVLCAPI.libvlc_media_player_new(libvlc_instance_); } else { string plugin_arg = "--plugin-path=" + pluginPath; string[] arguments = { "-I", "--fullscreen", "dummy", "--ignore-config", "--no-video-title", plugin_arg }; libvlc_instance_ = LIBVLCAPI.libvlc_new(arguments); libvlc_media_player_ = LIBVLCAPI.libvlc_media_player_new(libvlc_instance_); //float f1=0.1f; //LIBVLCAPI.libvlc_video_set_scale(libvlc_media_player_,f1); } } public void Vlc_release() { if (libvlc_instance_ != IntPtr.Zero) LIBVLCAPI.libvlc_release(libvlc_instance_); // if (libvlc_media_player_ != IntPtr.Zero) // LIBVLCAPI.libvlc_media_release(libvlc_media_player_); } public void SetRenderWindow(int wndHandle) { if (libvlc_instance_ != IntPtr.Zero && wndHandle != 0) { LIBVLCAPI.libvlc_media_player_set_hwnd(libvlc_media_player_, wndHandle); } } public void PlayFile(string filePath) { IntPtr libvlc_media = LIBVLCAPI.libvlc_media_new_path(libvlc_instance_, filePath); if (libvlc_media != IntPtr.Zero) { LIBVLCAPI.libvlc_media_parse(libvlc_media); duration_ = LIBVLCAPI.libvlc_media_get_duration(libvlc_media) / 1000.0; LIBVLCAPI.libvlc_media_player_set_media(libvlc_media_player_, libvlc_media); LIBVLCAPI.libvlc_media_release(libvlc_media); LIBVLCAPI.libvlc_media_player_play(libvlc_media_player_); } } public void PlayFile_rtsp(string filePath)//libvlc_media_new_location { IntPtr libvlc_media = LIBVLCAPI.libvlc_media_new_location(libvlc_instance_, filePath); if (libvlc_media != IntPtr.Zero) { // LIBVLCAPI.libvlc_media_parse(libvlc_media); // duration_ = LIBVLCAPI.libvlc_media_get_duration(libvlc_media) / 1000.0; LIBVLCAPI.libvlc_media_player_set_media(libvlc_media_player_, libvlc_media); LIBVLCAPI.libvlc_media_release(libvlc_media); LIBVLCAPI.libvlc_media_player_play(libvlc_media_player_); } } public void Pause() { if (libvlc_media_player_ != IntPtr.Zero) { LIBVLCAPI.libvlc_media_player_pause(libvlc_media_player_); } } public void take_snapshot() { if (libvlc_media_player_ != IntPtr.Zero) { string filepath = "c:\\"; LIBVLCAPI.libvlc_video_take_snapshot(libvlc_media_player_, 0, filepath, 0, 0); } } public void full_screen() { if (libvlc_media_player_ != IntPtr.Zero) { LIBVLCAPI.libvlc_set_fullscreen(libvlc_media_player_, 0); } } public void Stop() { if (libvlc_media_player_ != IntPtr.Zero) { LIBVLCAPI.libvlc_media_player_stop(libvlc_media_player_); } } public double GetPlayTime() { return LIBVLCAPI.libvlc_media_player_get_time(libvlc_media_player_) / 1000.0; } public void SetPlayTime(double seekTime) { LIBVLCAPI.libvlc_media_player_set_time(libvlc_media_player_, (Int64)(seekTime * 1000)); } public int GetVolume() { return LIBVLCAPI.libvlc_audio_get_volume(libvlc_media_player_); } public void SetVolume(int volume) { LIBVLCAPI.libvlc_audio_set_volume(libvlc_media_player_, volume); } public void SetFullScreen(bool istrue) { LIBVLCAPI.libvlc_set_fullscreen(libvlc_media_player_, istrue ? 1 : 0); } public double Duration() { return duration_; } public string Version() { return LIBVLCAPI.libvlc_get_version(); } }1.2static 声明 m_instance 优化效率 如下: #pragma once#include #include typedef SSIZE_T ssize_t;#include "vlc/vlc.h"#include struct libvlc_media_track_info_t;struct libvlc_media_t;struct libvlc_instance_t;struct libvlc_media_player_t;struct libvlc_event_t;class context;enum MediaState { NothingSpecial = 0, Opening = 1, Buffering = 2, Playing = 3, Paused = 4, Stopped = 5, Ended = 6, Error = 7};class TestVlcVideo {public: TestVlcVideo(); void init( std::function eventCallback); void setHwnd(const int64_t iHwnd) ; bool loadMedia(const char* &url) ; int play() ; void pause() ; void stop() ; void setRatio(const char* &ratio) ; int getVolume() ; int setVolume(const int volume) ; int getMediaState() ; libvlc_instance_t * getVlcInstance(); libvlc_media_player_t * getVlcMediaPlayer();private: static void vlcEvents(const libvlc_event_t *ev, void *param); static libvlc_instance_t *m_instance; libvlc_media_player_t *m_mediaPlayer = nullptr; int64_t m_durationMS; std::function m_eventCallback; MediaState m_currentMediaState;}; 上面 static 声明的 m_instance 是为了优化效率,不必每次播放视频的时候都新建。 这是第二步工作。 1.3封装 DLL 需要封装真正的 DLL 了,向C#暴露的也是这个类里面的方法。 #pragma oncetypedef int(*CallBackMediaState)(int);#ifdef DLLVLC_EXPORTS // 用来导出函数#define DLLVLC_API __declspec(dllexport)#else // 用来标识为导入函数,对于引用该头文件的外部模块来说dllimport这个标记对编译优化有作用#define DLLVLC_API __declspec(dllimport)#endif#include "Testvlcvideo.h"namespace TestVLCDLL {extern "C" { /* * @brief VLC Instance和Player实例初始化 * @param CallBackMediaState callback 回调函数为媒体播放状态 * @return 每次vlcInit会返回一个VLC的Player ID,此ID唯一,后面的接口都需要此ID找到对应的Player */ DLLVLC_API int vlcInit(CallBackMediaState callback); /* * @brief VLC 媒体加载接口 * @param int index PlayerID * @param const char *path 媒体路径 */ DLLVLC_API bool vlcLoad(int index, const char *path); /* * @brief 设置句柄,如不设置则为默认窗口播放 * @param const int64_t iHwnd windows窗口句柄 */ DLLVLC_API bool vlcSetHwnd(int index,const int64_t iHwnd); DLLVLC_API bool play(int index); DLLVLC_API bool pause(int index); DLLVLC_API bool stop(int index); /* * @brief 设置播放窗口比例 * @param 形如 16:9 4:3 等字符串 */ DLLVLC_API bool setRatio(int index,const char* ratio); /* * @brief 设置媒体播放音量 */ DLLVLC_API bool setVolume(int index, int volume); /* * @brief 获取媒体总时长 */ DLLVLC_API int64_t getMediaLength(int index); /* * @brief 获取当前播放状态 */ DLLVLC_API int getMediaState(int index); /* * @brief 销毁VLC Player */ DLLVLC_API bool vlcDisponse(int index); }} 首先在最开始定义了 CallBackMediaState 回调函数,对应C++ 层使用函数指针和std::function 都可以。然后使用 DLLVLC_EXPORTS 指示本类为导出类,然后再使用 DLLVLC_API 宏定义导出函数,这些方法都是 dll 暴露给外部调用的方法。 1.4应用程序的导出函数// DLLVLC.cpp : 定义 DLL 应用程序的导出函数。#define DLLVLC_EXPORTS#include "DLLVLC.h"#include "Testvlcvideo.h"#include #include #include #include std::map g_mapVLC;std::atomic_int g_iIndex = 0;std::mutex g_mt;DLLVLC_API int TestVLCDLL::vlcInit(CallBackMediaState callback){ //如果是初次调用,则初始化instance,否则复用instance std::lock_guard l(g_mt); ++g_iIndex; TestVlcVideo *vlcVideo = new TestVlcVideo; g_mapVLC.emplace(g_iIndex, vlcVideo); g_mapVLC.at(g_iIndex)->

Init (callback); return gimiIndex;} DLLVLC_API bool TestVLCDLL::play (int index) {std::lock_guard l (g_mt); TestVlcVideo * vlcVideo = g_mapVLC.at (index); if (nullptr = = vlcVideo) {return false;} vlcVideo- > play (); return true;}.

Because we use the method of exporting the interface instead of exporting the class (it is troublesome to export the class, and our test is unsuccessful), when creating the dll library, we use static map to save the relevant instances, and use the corresponding init method and dispose method to create and destroy objects with the help of id parameters.

Implementation of 1.5 vlc simple package

Let's take a look at the cpp file of our first piece of code, which is the concrete implementation of the simple encapsulation of vlc:

# include "Testvlcvideo.h" # include libvlc_instance_t * TestVlcVideo::m_instance = nullptr;TestVlcVideo::TestVlcVideo (): m_mediaPlayer (nullptr), m_durationMS (0), m_eventCallback (nullptr) {} void TestVlcVideo::init (std::function eventCallback) {getVlcInstance (); {getVlcMediaPlayer (); libvlc_event_manager_t * em = libvlc_media_player_event_manager (m_mediaPlayer) {libvlc_event_attach (em, libvlc_MediaPlayerPlaying, vlcEvents, this); libvlc_event_attach (em, libvlc_MediaPlayerPaused, vlcEvents, this); libvlc_event_attach (em, libvlc_MediaPlayerStopped, vlcEvents, this); libvlc_event_attach (em, libvlc_MediaPlayerNothingSpecial, vlcEvents, this); libvlc_event_attach (em, libvlc_MediaPlayerOpening, vlcEvents, this) Libvlc_event_attach (em, libvlc_MediaPlayerBuffering, vlcEvents, this); libvlc_event_attach (em, libvlc_MediaPlayerEndReached, vlcEvents, this); libvlc_event_attach (em, libvlc_MediaPlayerPositionChanged, vlcEvents, this);} m_eventCallback = std::move (eventCallback);} void TestVlcVideo::setHwnd (const int64_t iHwnd) {libvlc_media_player_set_hwnd (m_mediaPlayer, (void *) iHwnd) } bool TestVlcVideo::loadMedia (const char* & url) {libvlc_media_t * m_media = nullptr; std::string url_ = url; if (url_.find (": / /") = = std::string::npos) {m_media = libvlc_media_new_path (getVlcInstance (), url);} else {m_media = libvlc_media_new_location (getVlcInstance (), url) } if (nullptr = = m_media) {m_currentMediaState = MediaState::Error; return false;} libvlc_media_player_set_media (getVlcMediaPlayer (), m_media); libvlc_media_parse (m_media); m_durationMS = libvlc_media_get_duration (m_media); libvlc_media_release (m_media); return true } libvlc_instance_t * TestVlcVideo::getVlcInstance () {if (nullptr = = m_instance) {m_instance = libvlc_new (0, NULL);} return TestVlcVideo::getVlcMediaPlayer () {if (nullptr = = m_mediaPlayer) {m_mediaPlayer = libvlc_media_player_new (m_instance);} return m_mediaPlayer } int TestVlcVideo::play () {return libvlc_media_player_play (m_mediaPlayer);} void TestVlcVideo::pause () {if (libvlc_media_player_is_playing (m_mediaPlayer)) {libvlc_media_player_set_pause (m_mediaPlayer, 1);} else {libvlc_media_player_set_pause (m_mediaPlayer, 0);}}

At this point, we generally need to configure the def file to avoid adding additional information to the exported function name, rather than a short "play" and so on. But you can see that we have added the "extern C" logo in front of all the export functions. It means that these functions are compiled according to the C standard, because C++ 's function is overloaded, and each compiler is different, resulting in the compiled function name being (mangled name), and each varies, but C does not support overloading, so using unified compilation provisions, at the same time can also ensure that this function is correctly called by C, so we do not need to write def files to ensure that the function name will not be destroyed.

2. C# call

After briefly talking about the encapsulation of DLL on C++, let's sum up some of these points:

At least two files are required, one is the wrapper class for the specific implementation, and the other is the export method file. In this article, we do not use the class, but export the function directly.

Callback functions like this typedef int (* CallBackMediaState) (int); to define.

Export a file to add a macro dllexport

# ifdef DLLVLC_EXPORTS / / is used to export the function # define DLLVLC_API _ _ declspec (dllexport) # else / / to be marked as an import function. For external modules referencing the header file, dllimport is useful for compilation optimization # define DLLVLC_API _ _ declspec (dllimport) # endif

The export function adds an extern "C" DLLVLC_API declaration.

2.1C# callback function declaration and definition [DllImport (@ "C:\ Users\ HiWin10\ Desktop\ DLLVLC\ x64\ Release\ DLLVLC.dll", EntryPoint = "vlcInit", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = false, CallingConvention = CallingConvention.Cdecl) public extern static int vlcInit (DllcallBack pfun); [UnmanagedFunctionPointer (CallingConvention.Cdecl)] public delegate int DllcallBack (int MediaState)

The callback function of C # is delegate. You need to define the delegate DllcallBack in advance, and then we assume that it is approved by C++ and pass it as a parameter to vlcInit. We need to write the concrete implementation of this delegate function below:

Public static int CsharpCall (int MediaState) {Console.WriteLine (MediaState); return MediaState;}

When in use:

Static int index; static void Main (string [] args) {DllcallBack mycall; mycall = new DllcallBack (Program.CsharpCall); index = vlcInit (mycall);. }

It has been verified that the callback function in this way can be recognized by C++, corresponding to C++ 's std::function.

2.2C# exports ordinary function calls [DllImport (@ "C:\ Users\ HiWin10\ Desktop\ DLLVLC\ x64\ Release\ DLLVLC.dll", EntryPoint = "vlcLoad", CallingConvention = CallingConvention.Cdecl)] public extern static bool vlcLoad (int index, string path) [DllImport (@ "C:\ Users\ HiWin10\ Desktop\ DLLVLC\ x64\ Release\ DLLVLC.dll", EntryPoint = "vlcSetHwnd", CallingConvention = CallingConvention.Cdecl)] public extern static bool vlcSetHwnd (int index, int iHwnd)

The above is the loading method of the general export function of C #, which can be called directly in the main function.

Static int index; static void Main (string [] args) {DllcallBack mycall; mycall = new DllcallBack (Program.CsharpCall); index = vlcInit (mycall); Console.WriteLine (vlcLoad (index, @ "D:\ 1.mp4")); Console.WriteLine (getMediaLength (index)); play (index); setRatio (index, "16:9")

In fact, the call on the C # side is relatively simple. The above method is static loading. You need to put the dll of C++ under the bin directory of the C# project, but the author has not tried the dynamic loading method.

The whole process is completed, the way to use C++ encapsulation can use some strong libraries that only support clocked clients and C++ API, can also prevent decompilation, but also can make the code better layering and so on.

Thank you for reading! This is the end of the article on "how C++ encapsulates DLL for C# calls". I hope the above content can be of some help to you, so that you can learn more knowledge. if you think the article is good, you can share it out for more people to see!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report