2009-07-22 11 views
6

मेरे पास सादे पुराने सी ++ (कोई .NET/प्रबंधित कोड) में लिखी गई कोड लाइब्रेरी है और मैं इसका उपयोग करने वाले एप्लिकेशन को पोर्ट कर रहा हूं कोड सी #। मुझे दो विकल्पों का सामना करना पड़ रहा है:पोर्टिंग (अप्रबंधित) सी ++ से सी # बनाम सी ++ का उपयोग सी # अनुप्रयोग में डीएलएल के रूप में सी #+

  1. समान कार्यक्षमता प्राप्त करने के लिए सी #+ कोड में सी ++ कोड को फिर से लिखें;
  2. सी ++ को डीएलएल के रूप में संकलित करें और इसे सी # एप्लिकेशन में लाइब्रेरी के रूप में उपयोग करें।

मैं सी # के लिए अपेक्षाकृत नया हूं और सी # ऐप में एक अप्रबंधित कोड लाइब्रेरी का उपयोग करने के प्रभाव से बहुत अपरिचित हूं (या यदि कोई भी है)। कोड स्वयं आकार में मध्यम है; इसमें सी # में फिर से लिखने में कुछ ही दिन लगेंगे, लेकिन मेरा विचार यह है कि कोड को छोड़कर मुझे अन्य अनुप्रयोगों में इसका उपयोग करने की अनुमति मिल जाएगी (और इसे यूनिक्स पर संकलित करने के लिए)।

इस निर्णय के दौरान मुझे किस तरह की चीजों के बारे में पता होना चाहिए? सी # आवेदन में डीएलएल का उपयोग करने के लिए कोई बड़ी कमी या गेटचास हैं?

+1

मोनो आपको * पोर्ट पर "पोर्ट"/चलाने की अनुमति भी देगा। – Tim

उत्तर

6

मैं पुस्तकालय को सी # में प्रकट करने के लिए सी ++/सीएलआई का उपयोग करके एक रैपर लाइब्रेरी बनाउंगा। यह आपकी लाइब्रेरी को अपरिवर्तित छोड़ सकता है, और इसे .NET से उपयोग के लिए लपेट सकता है, जो दोनों विकल्पों में से सर्वश्रेष्ठ प्रदान करता है।

+1

मुझे 20 सेकंड तक मारो। लेकिन * मैं * गया और एक लिंक मिला। :) – Randolpho

+1

सी ++/सीएलआई रैपर का उपयोग करना * * जाने का तरीका है। पी/Invoke आपको डीएल लोडिंग और संस्करण मुद्दों को दे देंगे। एक अप्रबंधित लाइब्रेरी का उपयोग करके प्रबंधित अप्रबंधित संकलन के लिए रेखा स्पष्ट हो जाएगी। हालांकि, एसटीएल कक्षाओं को उजागर करने से सावधान रहें। आप पाते हैं कि आपका निम्न-स्तरीय कोड जो अप्रबंधित एसटीएल का उपयोग करने की अपेक्षा करता है, प्रबंधित संस्करणों का उपयोग करके कई प्रबंधित/अप्रबंधित संक्रमणों के साथ समाप्त हो जाएगा। – plinth

2

अप्रयुक्त सी ++ पुस्तकालयों से निपटने के दौरान C++/CLI में एक चीज उपयोगी हो गई है। सी ++/सीएलआई का उपयोग करके एक प्रबंधित रैपर बनाएं और इसे अपने सी # कोड से कॉल करें। प्रबंधित रैपर में पुस्तकालय (मुझे लगता है कि यह स्थिर रूप से जुड़ा हुआ है) में डीएलएल में शामिल हो सकता है, और एक परियोजना संदर्भ आपको अपने सी # कोड के लिए आवश्यक है।

+0

एफवाईआई: डीएलएल स्थिर रूप से जुड़े नहीं हैं। गतिशील लिंक लाइब्रेरी। – Amy

+1

@ yodaj007: मेरा मानना ​​है कि वह मूल पुस्तकालय को सी ++/सीएलआई असेंबली में स्थिर रूप से लिंक करने का सुझाव दे रहा था, जो सही है। –

+0

@ yodaj007: @Reed Copsey ने कहा कि यह मुझसे बेहतर हो सकता है। लेकिन मैं अभी भी कोशिश करूँगा: मूल प्रश्न में उल्लिखित चीजों के आधार पर मूल पुस्तकालय एक स्थिर रूप से जुड़ी लाइब्रेरी प्रतीत होता है। इसका अर्थ यह है कि अगर लाइब्रेरी का उपयोग सी ++/सीएलआई प्रोजेक्ट द्वारा किया जाता है, तो इसे सी ++/सीएलआई डीएलएल में संकलित (और कम किया जाएगा)। – Randolpho

0

सी ++/सीएलआई में एक रैपर लिखना आवश्यक नहीं है। आप सीधे सी # से प्लेटफार्म आह्वान का उपयोग कर सकते हैं:

http://msdn.microsoft.com/en-us/library/aa288468%28VS.71%29.aspx

संपादित करें: यदि आप इसके C++/CLI का उपयोग कर, तो आप LoadLibrary कॉल कर रहे हैं और समारोह संकेत बनाने की आवश्यकता होगी। यह सी # में काफी आसान है। इस MSDN ट्यूटोरियल ऊपर लिंक से है, लेकिन अपने ही जोड़ा टिप्पणी के साथ:

class PlatformInvokeTest 
{ 
    [DllImport("msvcrt.dll")] // Specify the DLL we're importing from 
    public static extern int puts(string c); // This matches the signature of the DLL function. The CLR automatically marshals C++ types to C# types. 
    [DllImport("msvcrt.dll")] 
    internal static extern int _flushall(); 

    public static void Main() 
    { 
     puts("Test"); 
     _flushall(); 
    } 
} 

संपादित करें: जटिल प्रकार भी, मार्शल किया जा सकता है, हालांकि यह structs परिभाषित करने के लिए आवश्यक है। यह उदाहरण मेरे अपने कोड से लिया गया है जो जीडीआई + को आमंत्रित करता है। मैंने इसे थोड़ा सा छीन लिया है।

private static int SRCCOPY = 0x00CC0020; 
private static uint BI_RGB = 0; 
private static uint DIB_RGB_COLORS = 0; 


[DllImport("gdi32.dll")] 
private static extern bool DeleteObject(IntPtr hObject); 

[StructLayout(LayoutKind.Sequential)] 
private struct BITMAPINFO 
{ 
    public uint biSize; 
    public int biWidth; 
    public int biHeight; 
    public short biPlanes; 
    public short biBitCount; 
    public uint biCompression; 
    public uint biSizeImage; 
    public int biXPelsPerMeter; 
    public int biYPelsPerMeter; 
    public uint biClrUsed; 
    public uint biClrImportant; 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)] 
    public uint[] cols; 
} 

public static Bitmap Downsample(Bitmap input, int bpp) 
{ 
    Bitmap retval = null; 

    // We will call into this GDI functionality from C#. Our plan: 
    // (1) Convert our Bitmap into a GDI hbitmap (ie. copy unmanaged->managed) 
    // (2) Create a GDI monochrome hbitmap 
    // (3) Use GDI "BitBlt" function to copy from hbitmap into monochrome (as above) 
    // (4) Convert the monochrone hbitmap into a Bitmap (ie. copy unmanaged->managed) 

    IntPtr inputHandle = input.GetHbitmap(); 

    // 
    // Step (2): create the monochrome bitmap. 
    // 
    BITMAPINFO bmi = new BITMAPINFO(); 
    bmi.biSize = 40; // the size of the BITMAPHEADERINFO struct 
    bmi.biWidth = input.Width; 
    bmi.biHeight = input.Height; 
    bmi.biPlanes = 1; 
    bmi.biBitCount = (short)bpp; // 1bpp or 8bpp 
    bmi.biCompression = BI_RGB; 
    bmi.biSizeImage = (uint)(((input.Width + 7) & 0xFFFFFFF8) * input.Height/8); 
    bmi.biXPelsPerMeter = 0; // not really important 
    bmi.biYPelsPerMeter = 0; // not really important 

    // 
    // Create the color palette. 
    // 
    uint numColors = (uint)1 << bpp; // 2 colors for 1bpp; 256 colors for 8bpp 
    bmi.biClrUsed = numColors; 
    bmi.biClrImportant = numColors; 
    bmi.cols = new uint[256]; 

    if (bpp == 1) 
    { 
     bmi.cols[0] = MAKERGB(0, 0, 0); 
     bmi.cols[1] = MAKERGB(255, 255, 255); 
    } 
    else 
    { 
     for (int i = 0; i < numColors; i++) 
     { 
      bmi.cols[i] = MAKERGB(i, i, i); 
     } 
    } 

    // 
    // Now create the indexed bitmap 
    // 
    IntPtr bits0; 
    IntPtr indexedBitmapHandle = CreateDIBSection(IntPtr.Zero, ref bmi, DIB_RGB_COLORS, out bits0, IntPtr.Zero, 0); 
    IntPtr sourceDC = GetDC(IntPtr.Zero); 
    IntPtr hdc = CreateCompatibleDC(sourceDC); 
    IntPtr hdc0 = CreateCompatibleDC(sourceDC); 

    SelectObject(hdc, inputHandle); 
    SelectObject(hdc0, indexedBitmapHandle); 

    BitBlt(hdc0, 0, 0, input.Width, input.Height, hdc, 0, 0, SRCCOPY); 

    retval = Bitmap.FromHbitmap(indexedBitmapHandle); 

    // 
    // Dispose of the crud 
    // 
    DeleteDC(hdc); 
    DeleteDC(hdc0); 
    ReleaseDC(IntPtr.Zero, sourceDC); 
    DeleteObject(inputHandle); 
    DeleteObject(indexedBitmapHandle); 

    return retval; 
} 
+0

यह काफी सरल दिखता है। एसटीएल कंटेनर और जटिल कस्टम प्रकार जैसी चीजों के मार्शलिंग के बारे में क्या? –

+3

आपको लोड लाइब्रेरी या फ़ंक्शन पॉइंटर्स से निपटने की आवश्यकता नहीं है - सी ++/सीएलआई एक जटिल सी ++ लाइब्रेरी सरल को लपेटता है।पी/महान काम करता है, बशर्ते पुस्तकालय एक सी एपीआई प्रदान करता है, लेकिन पी/Invoke का उपयोग कर सी ++ कक्षा उदाहरण को लपेटने के लिए कोई (आसान) तरीका नहीं है। यह सी के लिए बहुत अच्छा है, लेकिन सी ++ कक्षाओं के लिए इतना अच्छा नहीं है। –

+0

यदि आप अधिक जटिल संरचनाओं में गुजर रहे हैं, तो पी/Invoke हस्ताक्षर को समझना वास्तव में मुश्किल हो सकता है। एक प्रबंधित सी ++/सीएलआई डीएलएल में लपेटने से आप संरचनाओं को मार्शल करने के लिए एक व्यावहारिक तरीके से पता नहीं लगा सकते हैं, तो आप संरचनाओं को पारित कर सकते हैं। –

संबंधित मुद्दे