Skip to content

6.2 C# Accessing C99 SDK

Overview

C# applications can call C99 SDK dynamic library via DllImport (P/Invoke) for cross-language integration.

6.2.1 Prerequisites

DependencyDescription
.NETFramework 4.5+ or .NET Core 3.1+
C99 SDKc_arm_api.dll (Windows)

6.2.2 Minimal Example: Connect and Disconnect

csharp
using System;
using System.Runtime.InteropServices;

class Program
{
    [DllImport("c_arm_api.dll", CallingConvention = CallingConvention.Cdecl)]
    public static extern IntPtr Arm_Create();

    [DllImport("c_arm_api.dll", CallingConvention = CallingConvention.Cdecl)]
    public static extern void Arm_Destroy(IntPtr handle);

    [DllImport("c_arm_api.dll", CallingConvention = CallingConvention.Cdecl)]
    public static extern int Arm_Connect(IntPtr handle, string controllerIp, string teachPanelIp);

    [DllImport("c_arm_api.dll", CallingConvention = CallingConvention.Cdecl)]
    public static extern void Arm_Disconnect(IntPtr handle);

    static void Main(string[] args)
    {
        // Create handle
        IntPtr handle = Arm_Create();

        // Connect to robot
        int ret = Arm_Connect(handle, "10.27.1.2", "10.27.1.102");
        Console.WriteLine($"Connect result: {ret}");

        // Disconnect
        Arm_Disconnect(handle);

        // Destroy handle
        Arm_Destroy(handle);
        Console.WriteLine("Done");
    }
}

6.2.3 Object-Oriented Wrapper (Facade Pattern)

You can create an Arm class that wraps C99 functions into a C# object-oriented API:

csharp
using System;
using System.Runtime.InteropServices;

public class Arm : IDisposable
{
    private const string DllName = "c_arm_api.dll";
    private IntPtr _handle;

    [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
    private static extern IntPtr Arm_Create();

    [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
    private static extern void Arm_Destroy(IntPtr handle);

    [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
    private static extern int Arm_Connect(IntPtr handle, string controllerIp, string teachPanelIp);

    [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
    private static extern void Arm_Disconnect(IntPtr handle);

    public void Connect(string controllerIp, string teachPanelIp = null)
    {
        if (_handle == IntPtr.Zero)
            _handle = Arm_Create();
        int ret = Arm_Connect(_handle, controllerIp, teachPanelIp);
        if (ret != 0)
            throw new InvalidOperationException($"Connect failed: {ret}");
    }

    public void Disconnect()
    {
        if (_handle != IntPtr.Zero)
            Arm_Disconnect(_handle);
    }

    public void Dispose()
    {
        Disconnect();
        if (_handle != IntPtr.Zero)
        {
            Arm_Destroy(_handle);
            _handle = IntPtr.Zero;
        }
    }
}

// Usage example
using (var arm = new Arm())
{
    arm.Connect("10.27.1.2", "10.27.1.102");
    Console.WriteLine("Connected successfully");
}

6.2.4 Notes

  1. Calling Convention: C99 SDK uses cdecl , must specify CallingConvention = CallingConvention.Cdecl
  2. Platform Target: Ensure C# project platform target matches DLL (x64)
  3. DLL Path: Ensure DLL is in searchable path
  4. Thread Safety: Same handle cannot be accessed concurrently across threads
  5. BasScript Builder: C99 now exposes ArmBasScriptHandle and ArmBasExtraParamHandle , which are more suitable for C# object wrappers than manually assembling BAS script text arrays
  6. Builder Convenience Wrappers: Arm_BasScript_SetName / AppendLine(s) and Arm_BasValue_* map naturally to C# instance methods and static factories, reducing manual ArmBasValue assembly