6.2 C#에서 C99 SDK 연동
개요
C# 애플리케이션은 DllImport (P/Invoke)를 통해 C99 SDK 동적 라이브러리를 호출하여 언어 간 통합을 구현할 수 있습니다.
6.2.1 환경 준비
| 의존성 | 설명 |
|---|---|
| .NET | Framework 4.5+ 또는 .NET Core 3.1+ |
| C99 SDK | c_arm_api.dll (Windows) |
6.2.2 최소 예제: 연결 및 연결 해제
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)
{
// 핸들을 생성합니다.
IntPtr handle = Arm_Create();
// 로봇에 연결합니다.
int ret = Arm_Connect(handle, "10.27.1.2", "10.27.1.102");
Console.WriteLine($"연결 결과: {ret}");
// 연결을 해제합니다.
Arm_Disconnect(handle);
// 핸들을 파괴합니다.
Arm_Destroy(handle);
Console.WriteLine("완료");
}
}6.2.3 객체 지향 래퍼(퍼사드 패턴)
Arm 클래스를 만들어 C99 함수를 C# 객체 지향 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($"연결 실패: {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;
}
}
}
// 사용 예제
using (var arm = new Arm())
{
arm.Connect("10.27.1.2", "10.27.1.102");
Console.WriteLine("연결 성공");
}6.2.4 주의 사항
- 호출 규칙: C99 SDK는
cdecl을 사용하므로CallingConvention = CallingConvention.Cdecl을 지정해야 합니다. - 플랫폼 대상: C# 프로젝트의 플랫폼 대상이 DLL과 일치하는지 확인합니다(x64).
- DLL 경로: DLL이 검색 가능한 경로에 있는지 확인합니다.
- 스레드 안전: 같은 핸들을 여러 스레드에서 동시에 접근할 수 없습니다.
- BasScript Builder: C99는
ArmBasScriptHandle및ArmBasExtraParamHandle을 노출하므로, C# 측에서 객체화된 스크립트 구성 인터페이스로 래핑할 수 있습니다. - Builder 편의 래퍼:
Arm_BasScript_SetName/AppendLine(s)및Arm_BasValue_*는 C# 객체 메서드와 정적 팩토리로 매핑할 수 있습니다.