最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++ 封裝 DLL 供 C# 調用詳細介紹

 更新時間:2021年09月13日 16:47:15   作者:_q2nAmor  
這篇文章主要介紹了C++ 封裝 DLL 供 C# 調用(以C# 調用C++ 二次封裝的VLC播放庫為介質,支持回調函數(shù)的封裝),需要的朋友可以參考下面我文章的具體內容

1、VLC代碼封裝

1.1 QT(C++)工程

首先需要配置可使用 VLC 正常播放的 QT(C++)工程,獲取VLC每一幀并渲染到Qwidget

Libvlcapi

public static class LIBVLCAPI
    {

        #region[libvlc.dll 導出函數(shù)]

        // 創(chuàng)建一個libvlc實例,它是引用計數(shù)的
        [DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        private static extern IntPtr libvlc_new(int argc, IntPtr argv);

        // 釋放libvlc實例
        [DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern void libvlc_release(IntPtr libvlc_instance);

        [DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern String libvlc_get_version();

        // 從視頻來源(例如Url)構建一個libvlc_meida
        [DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        private static extern IntPtr libvlc_media_new_location(IntPtr libvlc_instance, IntPtr path);

        // 從視頻來源(例如Url)抓圖
        [DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        private static extern int libvlc_video_take_snapshot(IntPtr libvlc_mediaplayer, int num, IntPtr filepath, int i_width, int i_height);

        // 從本地文件路徑構建一個libvlc_media
        [DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        private static extern IntPtr libvlc_media_new_path(IntPtr libvlc_instance, IntPtr path);

        [DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern void libvlc_media_release(IntPtr libvlc_media_inst);

        // 創(chuàng)建libvlc_media_player(播放核心)
        [DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern IntPtr libvlc_media_player_new(IntPtr libvlc_instance);

        // 將視頻(libvlc_media)綁定到播放器上
        [DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern void libvlc_media_player_set_media(IntPtr libvlc_media_player, IntPtr libvlc_media);

        // 設置圖像輸出的窗口
        [DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern void libvlc_media_player_set_hwnd(IntPtr libvlc_mediaplayer, Int32 drawable);

        [DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern void libvlc_media_player_play(IntPtr libvlc_mediaplayer);

        [DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern void libvlc_media_player_pause(IntPtr libvlc_mediaplayer);

        [DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern void libvlc_media_player_stop(IntPtr libvlc_mediaplayer);

        // 解析視頻資源的媒體信息(如時長等)
        [DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern void libvlc_media_parse(IntPtr libvlc_media);

        // 返回視頻的時長(必須先調用libvlc_media_parse之后,該函數(shù)才會生效)
        [DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern Int64 libvlc_media_get_duration(IntPtr libvlc_media);

        // 當前播放的時間
        [DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern Int64 libvlc_media_player_get_time(IntPtr libvlc_mediaplayer);

        // 設置播放位置(拖動)
        [DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern void libvlc_media_player_set_time(IntPtr libvlc_mediaplayer, Int64 time);

        [DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern void libvlc_media_player_release(IntPtr libvlc_mediaplayer);

        // 獲取和設置音量
        [DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern int libvlc_audio_get_volume(IntPtr libvlc_media_player);

        [DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern void libvlc_audio_set_volume(IntPtr libvlc_media_player, int volume);

        // 設置全屏
        [DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern void libvlc_set_fullscreen(IntPtr libvlc_media_player, int isFullScreen);

        // 設置屏幕因子
        [DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern void libvlc_video_set_scale(IntPtr libvlc_media_player, float f_factor);

        #endregion

        #region[VLC方法]

        public struct PointerToArrayOfPointerHelper
        {
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)]
            public IntPtr[] pointers;
        }

        public static IntPtr libvlc_new(string[] arguments)
        {
            PointerToArrayOfPointerHelper argv = new PointerToArrayOfPointerHelper();
            argv.pointers = new IntPtr[11];

            for (int i = 0; i < 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 優(yōu)化效率

如下:

#pragma once
#include <memory>
#include <basetsd.h>
typedef SSIZE_T ssize_t;
#include "vlc/vlc.h"
#include <mutex>

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<void(int)> 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<void(int)> m_eventCallback;
    MediaState m_currentMediaState;
};

上面 static 聲明的 m_instance 是為了優(yōu)化效率,不必每次播放視頻的時候都新建。

這是第二步工作。

1.3封裝 DLL

需要封裝真正的 DLL 了,向C#暴露的也是這個類里面的方法。

#pragma once

typedef  int(*CallBackMediaState)(int);

#ifdef DLLVLC_EXPORTS // 用來導出函數(shù)
#define DLLVLC_API __declspec(dllexport)
#else // 用來標識為導入函數(shù),對于引用該頭文件的外部模塊來說dllimport這個標記對編譯優(yōu)化有作用
#define DLLVLC_API __declspec(dllimport)
#endif

#include "Testvlcvideo.h"

namespace TestVLCDLL {

extern "C" {
    /*
     *  @brief   VLC Instance和Player實例初始化
     *  @param   CallBackMediaState callback  回調函數(shù)為媒體播放狀態(tài)
     *  @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  獲取當前播放狀態(tài)
    */
    DLLVLC_API int   getMediaState(int index);
    /*
    *  @brief  銷毀VLC Player
    */
    DLLVLC_API bool  vlcDisponse(int index);

    }
}

首先在最開始定義了 CallBackMediaState 回調函數(shù),對應C++ 層使用函數(shù)指針和std::function 都可以。然后使用 DLLVLC_EXPORTS 指示本類為導出類,然后再使用 DLLVLC_API 宏定義導出函數(shù),這些方法都是 dll 暴露給外部調用的方法。

1.4應用程序的導出函數(shù)

// DLLVLC.cpp : 定義 DLL 應用程序的導出函數(shù)。
#define DLLVLC_EXPORTS
#include "DLLVLC.h"
#include "Testvlcvideo.h"
#include <iostream>
#include <map>
#include <mutex>
#include <atomic>

std::map<int, TestVlcVideo*> g_mapVLC;
std::atomic_int g_iIndex = 0;
std::mutex g_mt;

DLLVLC_API int TestVLCDLL::vlcInit(CallBackMediaState callback)
{
    //如果是初次調用,則初始化instance,否則復用instance
    std::lock_guard<std::mutex> l(g_mt);
    ++g_iIndex;
    TestVlcVideo *vlcVideo = new TestVlcVideo;
    g_mapVLC.emplace(g_iIndex, vlcVideo);
    g_mapVLC.at(g_iIndex)->init(callback);
    return g_iIndex;
}

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

.......


因為我們采用的是導出接口方法,而不是導出類(導出類比較麻煩,自己測試未能成功),因此在制作 dll 庫時,使用靜態(tài) map 保存相關實例,使用對應的 init方法和 dispose 方法借助 id 參數(shù)創(chuàng)建和銷毀對象。

1.5 vlc 簡單封裝的具體實現(xiàn)

下來再看下我們第一段代碼的 cpp 文件,就是 vlc 簡單封裝的具體實現(xiàn):

#include "Testvlcvideo.h"
#include <iostream>

libvlc_instance_t *TestVlcVideo::m_instance = nullptr;

TestVlcVideo::TestVlcVideo()
: m_mediaPlayer(nullptr)
, m_durationMS(0)
, m_eventCallback(nullptr)
{

}

void TestVlcVideo::init(std::function<void(int)> 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 m_instance;
}

libvlc_media_player_t * 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);
    }
}

到這兒,一般情況下我們還需要配置 def 文件,以避免導出的函數(shù)名被增加額外的信息,而不是簡短的“play”等。但是可以看到我們在所有的導出函數(shù)前增加了“extern C ”標識。意思是這些函數(shù)按照 C 標準進行編譯,由于C++ 的函數(shù)重載,再加上各個編譯器的不同,導致編譯而出的函數(shù)名被(mangled name),且各不相同,但是C不支持重載,因此采用統(tǒng)一的編譯規(guī)定,同時也可以保證此函數(shù)被 C 正確調用,所以我們就無需寫 def 文件也可以保證函數(shù)名不被破壞。

2、C# 調用

上面簡要說完了 C++ 端關于 DLL 的封裝,再總結一下大概就是這幾點:

  • 至少需要兩個文件,一個是自己對具體實現(xiàn)的封裝類,一個是導出方法文件,本文中我們沒有使用類,而是直接導出函數(shù)。
  • 回調函數(shù)像這樣 typedef int(*CallBackMediaState)(int); 去定義。
  • 導出文件添加宏 dllexport
#ifdef DLLVLC_EXPORTS // 用來導出函數(shù)
#define DLLVLC_API __declspec(dllexport)
#else // 用來標識為導入函數(shù),對于引用該頭文件的外部模塊來說dllimport這個標記對編譯優(yōu)化有作用
#define DLLVLC_API __declspec(dllimport)
#endif

導出函數(shù)添加 extern "C" DLLVLC_API 聲明。

2.1C# 回調函數(shù)聲明與定義

[DllImport(@"C:\Users\HiWin10\Desktop\DLLVLC\DLLVLC\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);
   

C# 的回調函數(shù)即為委托,需要提前定義委托 DllcallBack ,然后我們假定它是被 C++ 認可的,作為參數(shù)傳入 vlcInit。在下面我們需要寫此委托函數(shù)具體的實現(xiàn):

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

使用的時候:

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

經(jīng)過驗證,此種方式的回調函數(shù)能被 C++ 承認,對應于C++的 std::function。

2.2C# 導出普通函數(shù)調用

[DllImport(@"C:\Users\HiWin10\Desktop\DLLVLC\DLLVLC\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\DLLVLC\DLLVLC\x64\Release\DLLVLC.dll", EntryPoint = "vlcSetHwnd",
        CallingConvention = CallingConvention.Cdecl)]
        public extern static bool vlcSetHwnd(int index, int iHwnd);

上面是 C# 關于普通導出函數(shù)的加載方法,在 main 函數(shù)中直接進行調用即可。

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");

其實 C# 端的調用還是比較簡單的,上面的方式是采用靜態(tài)加載的方式,需要將C++ 的 dll 放到 C# 工程 bin 目錄下,而動態(tài)加載的方式筆者未進行嘗試。

整個過程就完成了,使用 C++ 封裝的方式可以使用一些只支持 C++,只有 C++ API 的強大庫,也可以防止反編譯,還可以使代碼更好的分層等。

下面附上demo鏈接,有需要的小伙伴可下載運行(VS2015)

DLLVLCfor_jb51.rar

到此這篇關于C++ 封裝 DLL 供 C# 調用詳細介紹的文章就介紹到這了,更多相關C++ 封裝 DLL 供 C# 調用內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • C++中perror和fprintf區(qū)別解析

    C++中perror和fprintf區(qū)別解析

    本文主要對比了C語言中的兩個函數(shù)perror和fprintf的區(qū)別,perror主要用于輸出與系統(tǒng)錯誤相關的消息,根據(jù)全局變量errno的值生成錯誤信息,而fprintf則用于格式化輸出任意類型的信息到指定的文件流
    2024-10-10
  • C語言實現(xiàn)簡單的三子棋項目

    C語言實現(xiàn)簡單的三子棋項目

    這篇文章主要為大家詳細介紹了C語言實現(xiàn)簡單的三子棋項目,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • 利用C語言替換文件中某一行的方法

    利用C語言替換文件中某一行的方法

    大家都知道C語言提供了文件操作,但是替換文件的某一行比較麻煩,下面是我使用的一個方法,現(xiàn)在分享給大家,有需要的朋友們可以參考借鑒。
    2016-09-09
  • C/C++實現(xiàn)日期計算器的示例代碼

    C/C++實現(xiàn)日期計算器的示例代碼

    本篇文章主要介紹了C/C++實現(xiàn)日期計算器的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-09-09
  • 深入理解c++20 concepts

    深入理解c++20 concepts

    本文主要介紹了深入理解c++20 concepts,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-06-06
  • C++ Boost PropertyTree解析INI文件詳解

    C++ Boost PropertyTree解析INI文件詳解

    Boost PropertyTree庫不僅可以解析JSON,XML格式,還可以直接解析INI格式文件。這篇文章就是為大家介紹一下如何通過Boost PropertyTree解析INI文件,需要的可以參考一下
    2022-01-01
  • 關于STL中set容器的一些總結

    關于STL中set容器的一些總結

    關于set,必須說明的是set關聯(lián)式容器。set作為一個容器也是用來存儲同一數(shù)據(jù)類型的數(shù)據(jù)類型,并且能從一個數(shù)據(jù)集合中取出數(shù)據(jù),在set中每個元素的值都唯一,而且系統(tǒng)能根據(jù)元素的值自動進行排序
    2013-09-09
  • 詳解C++編程中的sizeof運算符與typeid運算符

    詳解C++編程中的sizeof運算符與typeid運算符

    這篇文章主要介紹了C++編程中的sizeof運算符與typeid運算符,是C++入門學習中的基礎知識,需要的朋友可以參考下
    2016-01-01
  • C++實現(xiàn)靜態(tài)鏈表

    C++實現(xiàn)靜態(tài)鏈表

    這篇文章主要為大家詳細介紹了C++實現(xiàn)靜態(tài)鏈表,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-04-04
  • VC++獲得當前進程運行目錄的方法

    VC++獲得當前進程運行目錄的方法

    這篇文章主要介紹了VC++獲得當前進程運行目錄的方法,可通過系統(tǒng)函數(shù)實現(xiàn)該功能,是非常實用的技巧,需要的朋友可以參考下
    2014-10-10

最新評論

雷州市| 利辛县| 清丰县| 西畴县| 泾川县| 余姚市| 沙湾县| 昔阳县| 成武县| 红河县| 正定县| 崇礼县| 长兴县| 博野县| 岳普湖县| 积石山| 容城县| 县级市| 新民市| 藁城市| 聊城市| 临颍县| 肃宁县| 湟中县| 玉林市| 方山县| 勐海县| 宣化县| 项城市| 农安县| 涞源县| 合川市| 日照市| 友谊县| 青冈县| 剑川县| 长岛县| 桦川县| 马龙县| 昭平县| 雷山县|