C++ export function, bir DLL’in içindeki fonksiyonu dış dünyaya “açık” hale getirir. Böylece başka bir uygulama
o fonksiyonu isimle bulup çağırabilir. Bu yazıda export mantığını, __stdcall ve __cdecl farkını ve
Visual Studio ile yazdığımız C++ DLL fonksiyonunu C# tarafından (P/Invoke) nasıl çağıracağımızı net şekilde anlatıyorum.
Export function nedir?
- DLL içindeki bir fonksiyonu, başka programların çağırabilmesi için “dışa aktarma” işlemidir.
- Export edilen fonksiyonlar genelde isimle (export name) veya ordinal ile bulunur.
- Pratikte en yaygın yöntem:
__declspec(dllexport)ile export etmektir.
Ne işe yarar, kullanım amacı nedir?
Export function yaklaşımı, C++ ile yazdığın bir “çekirdek” kütüphaneyi başka projelerde yeniden kullanmanı sağlar. Özellikle performans kritik işler (işleme, şifreleme, görüntü/ ses, hesaplama), plugin mimarileri ve farklı dillerin (C#, Python vb.) native koda ihtiyaç duyduğu durumlarda çok tercih edilir.
DLL export, bir bakıma “kendi küçük WinAPI’ni yazmak” gibidir: dışarıya net bir fonksiyon imzası sunarsın, kullanıcı tarafı da o imzayı doğru şekilde çağırır.
Neden extern "C" kullanılır?
C++ derleyicisi fonksiyon isimlerini “name mangling” ile değiştirir (aşırı basit anlatımla: imzayı isme gömer).
C# gibi diller ise genelde export ismini düz haliyle arar. extern "C" kullanınca,
isim dönüştürme kapanır ve export adı stabil kalır.
__stdcall ve __cdecl farkı
Bu iki çağrı kuralı (calling convention) özellikle x86 (32-bit) hedeflerde kritiktir. Yanlış seçilirse stack bozulabilir ve uygulama çökebilir. x64 Windows tarafında fark pratikte çok azalır, ama yine de tutarlı bir seçim yapmak iyidir.
| Konu | __cdecl | __stdcall |
|---|---|---|
| Stack’i kim temizler? (x86) | Çağıran (caller) temizler | Çağrılan (callee) temizler |
| Kullanım | C/C++ genel varsayılan, varargs (printf) için uygun | WinAPI’de klasik olarak çok yaygın |
| C# DllImport | CallingConvention.Cdecl |
CallingConvention.StdCall |
Visual Studio ile C++ DLL yazma (export örneği)
- Visual Studio → New Project → Dynamic-Link Library (DLL) (C++) oluştur.
- Bir kaynak dosyası ekle:
MyNativeLib.cpp - Aşağıdaki gibi iki fonksiyon export et: biri
__stdcall, diğeri__cdecl
#define NOMINMAX
#include <Windows.h>
// Name mangling olmasın diye extern "C"
extern "C" __declspec(dllexport) int __stdcall Add(int a, int b)
{
return a + b;
}
extern "C" __declspec(dllexport) int __cdecl Mul(int a, int b)
{
return a * b;
}
C# tarafında isimle çağıracağımız için extern "C" kullanmak işi çok rahatlatır.
Ayrıca __stdcall / __cdecl eşleşmesini C# tarafında doğru vermek şarttır (özellikle x86’da).
C# tarafından export function çağırma (P/Invoke)
C# tarafında DLL fonksiyonunu çağırmanın en pratik yolu P/Invoke kullanmaktır.
Bunun için DllImport ile fonksiyon imzasını tanımlarsın. Burada kritik nokta,
CallingConvention değerinin C++ imzasıyla eşleşmesidir.
using System;
using System.Runtime.InteropServices;
class Program
{
// C++: __stdcall -> C#: StdCall
[DllImport("MyNativeLib.dll", CallingConvention = CallingConvention.StdCall)]
public static extern int Add(int a, int b);
// C++: __cdecl -> C#: Cdecl
[DllImport("MyNativeLib.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int Mul(int a, int b);
static void Main()
{
Console.WriteLine($"Add(2,3) = {Add(2,3)}");
Console.WriteLine($"Mul(4,5) = {Mul(4,5)}");
}
}
En sık hata: DLL bulunamadı
“DLL bulunamadı” hatasının en yaygın nedeni, MyNativeLib.dll dosyasının C# uygulamasının çalıştığı klasörde olmamasıdır.
Pratik çözüm: DLL’i C# projesinin çıktı klasörüne kopyalamaktır (ör. bin\Debug\netX\).
SSS
1) C++ sınıfını (class) export etmek mantıklı mı?
Genelde C# gibi dillerle en sorunsuz yol “C tarzı API”dir: extern "C" + basit fonksiyonlar.
Class export, ABI ve isim dönüştürme gibi konularda daha karmaşık hale gelebilir.
2) x64’te __stdcall / __cdecl farkı önemli mi?
Windows x64’te çağrı kuralı büyük ölçüde standarda bağlandığı için fark genelde kritik değildir. Ancak x86 hedeflerde kesinlikle önemlidir; bu yüzden projede tutarlı convention seçmek iyi pratiktir.
3) Export ismi neden bazen bulunamıyor?
En sık sebep name mangling’dir. extern "C" ekleyerek export adını stabil hale getirirsin.
Alternatif olarak .def dosyası ile export isimlerini kontrol edebilirsin.