Search This Blog

Monday, January 9, 2017

Creating Dynamic Link Library (DLL) in C++ and Using it in Visual Basic .NET

Visual Basic .NET 2012 (vs11) မှာသုံးဖို့ အတွက် DLL (Dynamic Link Library) တခုကို C++ နဲ့ ဖန်တီးဖို့ နည်းလမ်း ၂ ခု ကို ဆွေးနွေးချင်ပါတယ်။

  • CLR Class Library
  • Win32 DLL


  • CLR Class Library

    Visual Studio 2012 ကို ဖွင့်ပြီးတဲ့ အခါ New Project...InstalledTemplatesVisual C++CLRClass Library ကို ရွေးလိုက်ပါမယ်။ ပြီးရင် project name ၊ location နဲ့ solution name တွေကို လိုသလို ဖြည့်ပြီး OK ကိုနှိပ်နိုင်ပါတယ်။



    အောက်က အတိုင်း header နဲ့ C++ ကုဒ်တွေကို ရေးနိုင်ပြီး၊ solution ကို build ပါမယ်။



    // CppCLRDLL4VB.h
    
    #pragma once
    
    using namespace System;
    
    namespace CppCLRDLL4VB {
    
     public ref class Clrdlltest
     {
     public:
      double Add(double a,double b);
     };
    }
    


    // This is the main DLL file.
    // CppCLRDLL4VB.cpp
    
    #include "stdafx.h"
    
    #include "CppCLRDLL4VB.h"
    
    namespace CppCLRDLL4VB {
     double Clrdlltest::Add(double a,double b)
     {
      return a+b;
     }
    }
    


    ဒါဆိုရင် output folder ထဲမှာ DLL ဖိုင်ရလာပါမယ်။ သူ့ကို စမ်းသုံးကြည့်ဖို့ Visual Basic project အသစ်တခု ဖန်တီးလိုက်ပါမယ်။



    Solution explorer ထဲ က project ပေါ်မှာ ညာကလစ်ကို နှိပ်ပြီး Add Reference... ကနေ DLL ကို Browse လုပ် ထည့်ပြီးတဲ့ အခါ OK ကို နှိပ်ပါမယ်။



    အောက်က နမူနာ မှာ label တခုကို သုံးပြီး DLL function ရဲ့ ရလဒ်ကို ပြလိုက်ပါတယ်။



    Dim c As CppCLRDLL4VB.Clrdlltest = New CppCLRDLL4VB.Clrdlltest
    Label1.Text = c.Add(3, 4)
    


    Notes:

    CLR classes တွေရဲ့ရှေ့မှာ "Public ref"ထည့်ကြေငြာဖို့ လိုပါတယ်။ တကယ်လို့ array member ပါရင်
    int a[20];
    
    လို့ ကြေငြာ မယ့်အစား အောက်က ပြထားတဲ့ အတိုင်း ရေးဖို့ လိုပါတယ်။
    public ref class MyClass
     {
    public:
      MyClass() {a=new int[20];}
      !MyClass() {if(a) delete [] a;}
     private:
      int* a;
     };
    
    တကယ်လို့ function ရဲ့ arguments တွေ return values တွေမှာ object တွေသုံးမယ်ဆိုရင် အောက်မှာ ပြထားသလို ^ ထည့် ကြေငြာတာက လွယ်ကူတဲ့ နည်းတခုပါ။
    MyClass^ MyClass2::GetClass(MyClass^ a)
    {
     a->MemberFunc();
     return a;
    }
    
    String^ MyClass::ConvertStr(String^ s) 
    {
     String^ t="";
     string std="";
     for(int i=0;i < s->Length;i++){
      std+=(char)s[i];
     }
     
     for(unsigned int i=0;i < std.length();i++){
      t+=Convert::ToChar(std[i]).ToString();
     }
     t+=" :)";
     return t;
    }
    


    Win32 DLL

    Win32 DLL တခု ကို ဖန်တီးဖို့ အတွက် File on the menu bar → New Project.... Choose New Project...InstalledTemplatesVisual C++Win32Win32 Console Application ကို နှိပ်ပါမယ်။ပြီးရင် project name ၊ location နဲ့ solution name တွေကို လိုသလို ဖြည့်ပြီး OK ကိုနှိပ်နိုင်ပါတယ်။



    Win32 Application Wizard dialog box ရဲ့ Overview page မှာ Next ခလုပ်ကို နှိပ်ပါမယ်။ နောက် Application Settings page မှာ Application type အတွက် DLL ကိုရွေးပြီး Finish ခလုပ်ကို နှိပ်ပါမယ်။ နောက်ပြီး header ဖိုင်တခုကို ဖန်တီးဖို့ အတွက် PROJECT menu → Add New Item... ကို နှိပ်ပါမယ်။ ပေါ်လာတဲ့ dialog box မှာ Visual C++CodeHeader File (.h) ကို ရွေးပြီး ဖိုင်နာမည်တခု (CppWin32DLL4VB.h) ပေးပြီး Add ခလုပ်ကို နှိပ်နိုင်ပါတယ်။

    ပြီးရင် header နဲ့ C++ ကုဒ်တွေကို အောက်ကလို ရေးနိုင်ပါတယ်။



    // CppWin32DLL4VB.h
    
    #ifdef CPPWIN32DLL4VB_EXPORTS
    #define CPPWIN32DLL4VB_API __declspec(dllexport) 
    #else
    #define CPPWIN32DLL4VB_API __declspec(dllimport) 
    #endif
    
    namespace CppWin32DLL4VB {
    
     class Win32dlltest
     {
     public:
      static CPPWIN32DLL4VB_API double __stdcall Add(double a,double b);
     };
    }
    


    // CppWin32DLL4VB.cpp : Defines the exported functions for the DLL application.
    
    #include "stdafx.h"
    #include "CppWin32DLL4VB.h"
    
    namespace CppWin32DLL4VB {
     double Win32dlltest::Add(double a,double b)
     {
      return a+b;
     }
    }
    


    Project ကို ညာကလစ်နှိပ် Properties ကိုရွေးပြီး Property Pages dialog box ကို ဖွင့်လိုက်ပါမယ်။ ပြီးရင် Configuration PropertiesLinkerDebuggingGenerate Map File ကို Yes လို့ပြင်လိုက်ပါမယ်။ ဖိုင်နာမည်ကို တခုခု (CppWin32DLL4VB.map) ပေးပြီး OK နှိပ်ပါမယ်။ Solution ကို build လုပ်ကြည့်လိုက်ရင် map file က cpp တို့ h ဖိုင်တို့ ရှိတဲ့ sub folder ထဲမှာ ပေါ်လာပါမယ်။ သူ့ကို ဖွင့်ကြည့်ပြီး Add function ရဲ့ decorated name ကို ရှာကြည့်တဲ့ အခါ ဒီနမူနာမှာ'?Add@Win32dlltest@CppWin32DLL4VB@@SGNNN@Z' လို့ တွေ့နိုင်ပါတယ်။



    အဲ့ဒီ map file ရှိတဲ့ folder မှာပဲ .def extension နဲ့ ဖိုင်အသစ်တခု (CppWin32DLL4VD.def) ကို ဖန်တီးလိုက်ပါမယ်။ ပြီးရင် အောက်ကကုဒ် တွေကို ဖြည့်လိုက်ပါမယ်။

    EXPORTS  
       Add=?Add@Win32dlltest@CppWin32DLL4VB@@SGNNN@Z 
    


    ပြီးရင် project ရဲ့ Property Pages dialog box ကို ပြန်ဖွင့်ပြီး Configuration PropertiesLinkerInputModule Definition File မှာ ခုနက ဖန်တီးထားတဲ့ .def ကို သတ်မှတ်လိုက်ပါမယ်။



    Solution ကို build လုပ်လိုက်ရင် .sln file ရှိတဲ့ output folder ထဲမှာ DLL နဲ့ lib ဖိုင်တွေ ရလာပါမယ်။

    ရလာတဲ့ DLL ကို C++ နဲ့ အရင်စမ်းကြည့်ဖို့ အတွက် New Project...InstalledTemplatesVisual C++Win32Win32 Console Application ကို ရွေးပြီး Visual C++ console project တခုကို ဖန်တီးလိုက်ပါမယ်။



    Application Settings page ရဲ့ Application type မှာ console application ကို ရွေးပြီး Finish ခလုပ်ကို နှိပ်လိုက်ပါမယ်။ Project ကို ညာကလစ်နှိပ် Properties ကိုရွေးပြီး Property Pages dialog box ကို ဖွင့်လိုက်ပါမယ်။ ပြီးရင် header file (CppWin32DLL4VB.h) ရှိတဲ့ folder ကို Configuration PropertiesC/C++GeneralAdditional Include Directories မှာ သတ်မှတ်ပါမယ်။



    နောက်တခါ library file (CppWin32DLL4VB.lib) ရှိတဲ့ folder ကို Configuration PropertiesLinkerGeneralAdditional Include Directories မှာ သတ်မှတ်ပါမယ်။



    linker ကသုံးရမယ့် library နာမည် (CppWin32DLL4VB.lib) ကို LinkerInputAdditional Dependencies မှာ ထည့်ပါမယ်။ ပြီးရင် DLL file (CppWin32DLL4VB.dll) ကို output folder ထဲမှာ ကူးထည့်ထားလိုက်ပါမယ်။ နောက် C++ source file (Win32DLLVC.cpp) ကို အောက်ကလို ရေးနိုင်ပါတယ်။
    // Win32DLLVC.cpp : Defines the entry point for the console application.
    //
    
    #include "stdafx.h"
    #include < iostream >
    #include "CppWin32DLL4VB.h"
    using namespace std;
    using namespace CppWin32DLL4VB;
    int _tmain(int argc, _TCHAR* argv[])
    {
     double c;
     c=Win32dlltest::Add(5,4);
     cout << c << endl;
     return 0;
    }
    


    ပြီးခဲ့တဲ့ section ကလိုပဲ DLL ကို စမ်းကြည့်ဖို့ အတွက် Visual Basic program တခုကို ဖန်တီးလိုက်ပါမယ်။ DLL file (CppWin32DLL4VB.dll) ကိုလည်း output folder ထဲမှာ ကူးထည့်ထားလိုက်ပါမယ်။ ရလဒ်ကို ပြဖို့ အတွက် label တခုကိုလည်း Form ပေါ်မှာ ထည့်ထားလိုက်ပါမယ်။



    Form ကို Double click နှိပ်ပြီး 'Form1.vb' မှာ အောက်မှာ ပြထားတဲ့ VB code တွေထဲက တခုခု ကို သုံးပြီး စမ်းကြည့်နိုင်ပါတယ်။
    Public Class Form1
        Public Declare Function Add Lib "CppWin32DLL4VB.dll" Alias "Add" (ByVal a As Double, ByVal b As Double) As Double
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Label1.Text = Add(5, 4)
        End Sub
    End Class
    



    Imports System.Runtime.InteropServices
    Public Class Form1
        < DllImportAttribute("CppWin32DLL4VB.dll", EntryPoint:="Add",
        SetLastError:=True, CharSet:=CharSet.Unicode,
        ExactSpelling:=True,
        CallingConvention:=CallingConvention.StdCall) >
        Public Shared Function Add(ByVal a As Double, ByVal b As Double) As Double
            ' Leave this function empty. The DLLImport attribute forces calls to be forwarded.
        End Function
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Label1.Text = Add(5, 4)
        End Sub
    End Class
    


    References:

    https://msdn.microsoft.com/en-us/library/ms235636(v=vs.110).aspx

    https://msdn.microsoft.com/en-us/library/dt232c9t(v=vs.110).aspx

    [3] https://blog.mythicsoft.com/2008/03/05/36/

    No comments:

    Post a Comment