Put the C# project and the C Dll project under the same solution, so that you can realize the linkage debugging and enter the C Dll function directly from C#.
/// \brief set log level and path
/// \param log_level log level
/// \param szLogDir log save path
/// \see ZegoScreenCaptureLogLevel
extern "C" __declspec(dllexport) void zego_screencapture_set_log_level(enum ZegoScreenCaptureLogLevel log_level, const char *szLogDir);
Use the DLLImport method to call the unmanaged dynamic library.
//The path where DllImport dll is located
//The name of the EntryPoint function, you don’t need to write it
//SetLastError whether to keep the last error code of win32
//Expression of strings in CharSet dll
//CallingConvention function calling convention
[DllImport("ZegoScreenCapture.dll", EntryPoint = "zego_screencapture_set_log_level" SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern void zego_screencapture_set_log_level(ZegoScreenCaptureLogLevel level, string path);
The function calling convention is explained as follows:
Calling Convention | Description |
---|---|
Cdecl | The caller cleans up the stack. This enables developers to call functions with varargs (such as Printf), making them available for methods that accept a variable number of parameters. |
FastCall | This calling convention is not supported. |
StdCall | The callee cleans up the stack. This is the default convention for using platform invoke to call unmanaged functions. |
ThisCall | The first parameter is the this pointer, which is stored in the register ECX. Other parameters are pushed onto the stack. This calling convention is used to call methods on classes exported from unmanaged DLLs. |
Winapi | This member is not actually a calling convention, but uses the default platform calling convention. For example, the default is StdCall on Windows. The default on CE.NET is Cdecl. |
The corresponding list of types in C/C++ and C# is as follows:
C/C++ | C# |
---|---|
void* | IntPtr |
unsigned char | Byte |
short | Int16 |
unsigned short | UInt16 |
int | Int32 |
int* | IntPtr |
unsigned int | UInt32 |
long | Int32 |
long long | Int64 |
unsigned long | UInt32 |
unsigned long long | UInt64 |
char | Char |
char*, wchar_t*, const char*, const wchar_t* | String |
float | Single |
double | Double |
VARIANT | Object |
int&, int* output parameters | ref int |
Structure | public struct Structure{} |
Structure & | ref Structure |
Structure** | out Structure |
int i[10] | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] int[] i |
char buffer[10] | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] string buffer |
The following example demonstrates the structure and function prototype declared in the C interface.
struct ZegoScreenCaptureRect
{
int left; ///< abscissa of upper left corner
int top; ///< ordinate of the upper left corner
int right; ///< abscissa of the lower right corner
int bottom; ///< ordinate of the bottom right corner
};
/// \brief Get the coordinates of the specified window relative to the screen
/// \param handle Windows platform is the window handle, which can be obtained through zego_screencapture_enum_window_list
/// \param rect coordinate rectangle
/// \return When the window is invalid or the window is minimized and hidden, etc., it returns false when the coordinates are invalid, and returns true when the actual coordinates are obtained
SCREENCAPTURE_API bool zego_screencapture_get_window_rect(ZegoWindowHandle handle, struct ZegoScreenCaptureRect* rect);
C# structures and function prototype corresponding to the C interface.
The C# structure layout needs to be consistent with the C structure.
[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
public struct ZegoScreenCaptureRect
{
public int left;
public int top;
public int right;
public int bottom;
}
[DllImport("ZegoScreenCapture.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern bool zego_screencapture_get_window_rect(IntPtr handle, ref ZegoScreenCaptureRect rect);
The following example demonstrates how C# calls the C method. ref rect
represents the incoming structure pointer.
ZegoScreenCaptureRect rect = new ZegoScreenCaptureRect();
ScreenCaptureManager.zego_screencapture_get_window_rect(m_windows[this.comboBoxWindow.SelectedIndex], ref rect);
The following example demonstrates the C interface declaration method. handle_list
is a pointer to an array of window handles.
/// \brief Specify windows, filter these windows when capturing the screen, and not display them on the screen
/// \param handle_list List of window handles to be filtered, only windows with layered attribute specified under win7 can be filtered
/// \param count the number of windows
/// \param add true to add the filter window, false to remove the filter window
/// \note 1. [window setSharingType:NSWindowSharingNone] filtering can be set under macOS.
/// 2. Only use zego_screencapture_set_target_window filter to take effect under macOS.
/// Filtering using zego_screencapture_set_target_screen under macOS does not take effect.
SCREENCAPTURE_API void zego_screencapture_set_excluded_windows(ZegoWindowHandle* handle_list,int count,bool add);
The following example demonstrates how to import C interface in C#. IntPtr[] handle_list
corresponds to ZegoWindowHandle* handle_list
in C interface.
[DllImport("ZegoScreenCapture.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void zego_screencapture_set_excluded_windows( IntPtr[] handle_list, int count, bool add);
C# calls the C interface to set the filtered window list.
private void buttonRemoveExcludeWindow_Click(object sender, EventArgs e)
{
//Remove the collection filter window
IntPtr[] handle_list = new IntPtr[1];
handle_list[0] = m_windows2[this.comboBoxWindow2.SelectedIndex];
ScreenCaptureManager.zego_screencapture_set_excluded_windows(handle_list, 1, false);
}
The following example demonstrates the structure and function prototype declared in the C interface. The interface returns a pointer to the window information array.
struct ZegoScreenCaptureWindowItem
{
ZegoWindowHandle handle; ///< window unique identifier
char title[256]; ///< window title
char image_path[256]; ///< The path where the window corresponds to the process
}
/// \brief Synchronously enumerate the window list, including the window title and the corresponding executable file name of the window
/// \param isIncludeIconic Whether to include the minimized window when enumerating. Non-zero means include the minimized window, otherwise it does not include the minimized window.
/// \param count the number of windows
/// \return The first address of the window list, need to pair to call zego_screencapture_free_window_list to release
/// \note You can get the window that needs to be shared through the thumbnail related interface
/// \see zego_screencapture_free_window_list
SCREENCAPTURE_API const struct ZegoScreenCaptureWindowItem* zego_screencapture_enum_window_list(int isIncludeIconic, uint32_t *count);
C# declares the structure and function prototype corresponding to the C interface. The return value type is "IntPtr". When using it, you can use the pointer offset to get each item in the array.
[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
public struct ZegoScreenCaptureWindowItem
{
public IntPtr handle;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string title;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string image_path;
};
[DllImport("ZegoScreenCapture.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr zego_screencapture_enum_window_list(int isIncludeIconic, ref uint count);
C# calls the C interface to obtain the window information array, and uses the pointer offset windowsPtr + Marshal.SizeOf<ZegoScreenCaptureWindowItem>() * i
to obtain the information of each window in the array.
private void buttonRefreshWindow_Click(object sender, EventArgs e)
{
//Get the window list
m_windows.Clear();
m_windows2.Clear();
this.comboBoxWindow.Items.Clear();
this.comboBoxWindow2.Items.Clear();
uint count = 0;
//windowsPtr is a pointer to a structure array in C
IntPtr windowsPtr = ScreenCaptureManager.zego_screencapture_enum_window_list(1, ref count);
if (count> 0)
{
for (int i = 0; i <count; i++)
{
//Get the pointer of each item in the array by pointer offset
var Ptr = windowsPtr + Marshal.SizeOf<ZegoScreenCaptureWindowItem>() * i;
//Convert the structure pointer in C to C# structure object
window = (ZegoScreenCaptureWindowItem)Marshal.PtrToStructure(Ptr, typeof(ZegoScreenCaptureWindowItem));
//Because the string returned by the SDK is utf8 encoding, it needs to be converted to the default encoding of C#
this.comboBoxWindow.Items.Add(Encoding.UTF8.GetString(Encoding.Default.GetBytes(window.title)));
this.comboBoxWindow2.Items.Add(Encoding.UTF8.GetString(Encoding.Default.GetBytes(window.title)));
m_windows.Add(window.handle);
m_windows2.Add(window.handle);
}
}
this.comboBoxWindow.SelectedIndex = 0;
this.comboBoxWindow2.SelectedIndex = 0;
//Call the C method to release the structure array
ScreenCaptureManager.zego_screencapture_free_window_list(windowsPtr);
}
The C interface declares callback prototypes and methods for registering callbacks.
/// \brief Collection error callback
/// \param error error code
/// \param user_data user-defined data
/// \see ZegoScreenCaptureCaptureError
typedef void (*zego_screencapture_capture_error_notify_func)(enum ZegoScreenCaptureCaptureError error, void *data);
/// \brief Register collection exception notification
/// \param notify notification function
/// \param data User-defined data, transparently transmitted when callback
SCREENCAPTURE_API void zego_screencapture_reg_capture_error_notify(zego_screencapture_capture_error_notify_func notify, void *data);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void zego_screencapture_capture_error_notify_func(ZegoScreenCaptureCaptureError error, IntPtr user_data);
[DllImport("ZegoScreenCapture.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void zego_screencapture_reg_capture_error_notify(zego_screencapture_capture_error_notify_func notify, IntPtr data);
//Define the delegate object
ScreenCaptureManager.zego_screencapture_capture_error_notify_func m_zego_screencapture_capture_error_notify;
//Save the callback implementation method in the delegate object
m_zego_screencapture_capture_error_notify = new ScreenCaptureManager.zego_screencapture_capture_error_notify_func(zego_screencapture_capture_error_notify);
//The object must be registered here, the function name cannot be passed directly
ScreenCaptureManager.zego_screencapture_reg_capture_error_notify(m_zego_screencapture_capture_error_notify, IntPtr.Zero);
public void zego_screencapture_capture_error_notify(ZegoScreenCaptureCaptureError error, IntPtr user_data)
{
//Switch to C# thread
DoInMainThread(() =>
{
showMsg("error");
});
}
Because the execution of the callback is in the SDK thread, it is necessary to switch the execution of the callback to the C# thread to avoid multi-threaded access conflicts.
private delegate void DoInMainThreadDelegate();
private void DoInMainThread(DoInMainThreadDelegate func)
{
this.Invoke(func);
}
Screen sharing C# sample source code includes screen sharing, window sharing, area sharing and other functions. It shows how to call the C interface in C# to realize screen capture and streaming. Developers can refer to its usage to implement their own business. Please refer to Sample Code.