ডিএলএক্সপোর্টের সাথে একটি ডিএলএল থেকে ফাংশন রফতানি করা হচ্ছে


105

আমি একটি সি ++ উইন্ডোজ ডিএলএল থেকে কোনও ফাংশন রফতানির একটি সাধারণ উদাহরণ চাই।

আমি শিরোনাম, .cppফাইল এবং ফাইলটি দেখতে চাই .def(যদি একেবারে প্রয়োজন হয়)।

আমি চাইবে রফতানির নামটি অকেজো করা হোক । আমি সর্বাধিক স্ট্যান্ডার্ড কলিং কনভেনশন ( __stdcall?) ব্যবহার করতে চাই । আমি ব্যবহারটি চাই __declspec(dllexport)এবং একটি .defফাইল ব্যবহার করতে হবে না ।

উদাহরণ স্বরূপ:

  //header
  extern "C"
  {
   __declspec(dllexport) int __stdcall foo(long bar);
  }

  //cpp
  int __stdcall foo(long bar)
  {
    return 0;
  }

আমি লিঙ্কারটিকে নামের সাথে আন্ডারস্কোর এবং / বা সংখ্যাগুলি (বাইট গণনা?) যোগ করার চেষ্টা করছি।

আমি একই হেডার সমর্থন dllimportএবং dllexportব্যবহার না করে ঠিক আছে । আমি সি ++ শ্রেণির পদ্ধতিগুলি রফতানি সম্পর্কে কোনও তথ্য চাই না, কেবল সি স্টাইলের বৈশ্বিক ফাংশন।

হালনাগাদ

কলিং কনভেনশনকে অন্তর্ভুক্ত না করে (এবং ব্যবহার করে extern "C") আমার পছন্দমতো রফতানির নাম দেয় তবে এর অর্থ কী? ডিফল্ট কলিং কনভেনশন কি আমি পিনভোক (। নেট), ডিক্লেয়ার (ভিবি 6) পেয়ে যাচ্ছি এবং GetProcAddressআশা করব? (আমার ধারণা, GetProcAddressএটি কলার তৈরি ফাংশন পয়েন্টারের উপর নির্ভর করবে)।

আমি চাই যে এই ডিএলএলটি কোনও শিরোনামের ফাইল ছাড়াই ব্যবহার করা হোক, তাই #definesকোনও কলার দ্বারা শিরোনামকে ব্যবহারযোগ্য করে তোলার জন্য সত্যিকারের প্রচুর অভিনব প্রয়োজন আমার প্রয়োজন নেই ।

আমি একটি *.defফাইল ব্যবহার করতে হবে যে একটি উত্তরের সাথে আমি ঠিক আছি ।


আমি ভুল মনে রাখতে পারি তবে আমার মনে হয়: ক) extern Cফাংশনটির প্যারামিটারের ধরণগুলি বর্ণনা করে এমন সাজসজ্জা সরিয়ে দেবে, তবে সেই সজ্জা নয় যা ফাংশনটির আহ্বানের সম্মেলন বর্ণনা করে; খ) সমস্ত সজ্জা অপসারণ করতে আপনাকে একটি ডিইএফ ফাইলে (অজানা) নাম নির্দিষ্ট করতে হবে।
ক্রিসডাব্লু 11:39

এটি আমি পাশাপাশি দেখছিলাম। সম্ভবত আপনি এটি একটি পূর্ণ উত্তর হিসাবে যুক্ত করা উচিত?
আর্দভার্ক

উত্তর:


134

আপনি যদি সরল সি রফতানি চান তবে সি ++ নয় একটি সি প্রকল্প ব্যবহার করুন। সি ++ ডিএলএল সমস্ত সি ++ টি আইএসএম (নেমস্পেস ইত্যাদি ...) এর নাম-ম্যাংলিংয়ের উপর নির্ভর করে। সি / সি ++ -> অ্যাডভান্সড এর অধীনে আপনার প্রকল্প সেটিংসে গিয়ে আপনি আপনার কোডটি সি হিসাবে সংকলন করতে পারেন, সেখানে একটি বিকল্প আছে "সংকলন করুন" যা সংকলক সুইচ / টিপি এবং / টিসির সাথে সম্পর্কিত।

আপনি যদি এখনও আপনার লাইবের অভ্যন্তরীণ লেখার জন্য সি ++ ব্যবহার করতে চান তবে সি ++ এর বাইরে ব্যবহারের জন্য অবিচ্ছিন্ন কিছু ফাংশন রফতানি করেন তবে নীচের দ্বিতীয় বিভাগটি দেখুন।

ভিসি ++ এ ডিএলএল লিবস রফতানি / আমদানি করা হচ্ছে

আপনি যা করতে চান তা হ'ল শিরোনামের শর্তযুক্ত ম্যাক্রো সংজ্ঞায়িত করা যা আপনার ডিএলএল প্রকল্পের সমস্ত উত্স ফাইলগুলিতে অন্তর্ভুক্ত থাকবে:

#ifdef LIBRARY_EXPORTS
#    define LIBRARY_API __declspec(dllexport)
#else
#    define LIBRARY_API __declspec(dllimport)
#endif

তারপরে এমন কোনও ফাংশনে যা আপনি রফতানি করতে চান তা আপনি ব্যবহার করুন LIBRARY_API:

LIBRARY_API int GetCoolInteger();

আপনার লাইব্রেরি বিল্ড প্রকল্পে একটি সংজ্ঞা তৈরি করুন এটি LIBRARY_EXPORTSআপনার ডিএলএল বিল্ডের জন্য আপনার ফাংশনগুলি রফতানি করবে।

যেহেতু LIBRARY_EXPORTSডিএলএল গ্রহণকারী কোনও প্রকল্পে সংজ্ঞায়িত করা হবে না, যখন সেই প্রকল্পটিতে আপনার গ্রন্থাগারের হেডার ফাইল অন্তর্ভুক্ত থাকে তবে পরিবর্তে সমস্ত ফাংশন আমদানি করা হবে।

আপনার লাইব্রেরি যদি ক্রস প্ল্যাটফর্ম হতে হয় তবে আপনি উইন্ডোজ না থাকাকালীন LIBRARY_API কে কিছুই হিসাবে সংজ্ঞায়িত করতে পারেন:

#ifdef _WIN32
#    ifdef LIBRARY_EXPORTS
#        define LIBRARY_API __declspec(dllexport)
#    else
#        define LIBRARY_API __declspec(dllimport)
#    endif
#elif
#    define LIBRARY_API
#endif

Dllexport / dllimport ব্যবহার করার সময় আপনাকে DEF ফাইল ব্যবহার করার দরকার নেই, আপনি যদি DEF ফাইল ব্যবহার করেন তবে dllexport / dllimport ব্যবহার করার দরকার নেই। দুটি পদ্ধতি একই কাজটি বিভিন্ন উপায়ে সম্পন্ন করে, আমি বিশ্বাস করি যে দুজনের মধ্যে dllexport / dllimport হল প্রস্তাবিত পদ্ধতি।

লোডলিবারি / পিনভোকের জন্য সি ++ ডিএলএল থেকে আনম্যাঙ্গেল ফাংশন রফতানি করা হচ্ছে

আপনার যদি লোডলিবারি এবং গেটপ্রোক অ্যাড্রেস ব্যবহার করার প্রয়োজন হয়, বা অন্য কোনও ভাষা থেকে आयात করা যেতে পারে (অর্থাত্। নেট থেকে পিনভোক, বা পাইথন / আর এফএফআই ইত্যাদি) আপনি extern "C"সি ++ সংকলককে নামগুলি না ছড়িয়ে দেওয়ার জন্য আপনার dllexport এর সাথে ইনলাইন ব্যবহার করতে পারেন । এবং যেহেতু আমরা ডেলিম্পোর্টের পরিবর্তে গেটপ্রোকএড্রেস ব্যবহার করছি আমাদের উপরের থেকে ইফদেফ নাচ করার দরকার নেই, কেবল একটি সরল ডিলেক্সপোর্ট:

কোড:

#define EXTERN_DLL_EXPORT extern "C" __declspec(dllexport)

EXTERN_DLL_EXPORT int getEngineVersion() {
  return 1;
}

EXTERN_DLL_EXPORT void registerPlugin(Kernel &K) {
  K.getGraphicsServer().addGraphicsDriver(
    auto_ptr<GraphicsServer::GraphicsDriver>(new OpenGLGraphicsDriver())
  );
}

এবং ডাম্পবিন / রফতানির সাথে রফতানির মতো দেখতে এখানে রয়েছে:

  Dump of file opengl_plugin.dll

  File Type: DLL

  Section contains the following exports for opengl_plugin.dll

    00000000 characteristics
    49866068 time date stamp Sun Feb 01 19:54:32 2009
        0.00 version
           1 ordinal base
           2 number of functions
           2 number of names

    ordinal hint RVA      name

          1    0 0001110E getEngineVersion = @ILT+265(_getEngineVersion)
          2    1 00011028 registerPlugin = @ILT+35(_registerPlugin)

সুতরাং এই কোডটি সূক্ষ্মভাবে কাজ করে:

m_hDLL = ::LoadLibrary(T"opengl_plugin.dll");

m_pfnGetEngineVersion = reinterpret_cast<fnGetEngineVersion *>(
  ::GetProcAddress(m_hDLL, "getEngineVersion")
);
m_pfnRegisterPlugin = reinterpret_cast<fnRegisterPlugin *>(
  ::GetProcAddress(m_hDLL, "registerPlugin")
);

1
বাহ্যিক "সি" দেখে মনে হয়েছিল যে সি ++ শৈলীর নাম ম্যাংলিং সরিয়ে দেওয়া হয়েছে। সম্পূর্ণ আমদানি বনাম রফতানি জিনিস (যা আমি প্রশ্নের মধ্যে না থাকার পরামর্শ দেওয়ার চেষ্টা করেছি) আসলে আমি যা চাইছি তা নয় (তবে এটির ভাল তথ্য)। আমি বুঝতে পেরেছিলাম যে সমস্যা মেঘ হবে।
আর্ডওয়ার্ক

আমি কেবলমাত্র এটিই ভাবতে পারি যে এটি আপনার প্রয়োজন হবে লোডলিবারি এবং গেটপ্রোক অ্যাড্রেসগুলির জন্য ... এটি ইতিমধ্যে যত্ন নেওয়া হয়েছে, আমি আমার উত্তর শরীরে ব্যাখ্যা করব ...
জোশফেরি

এক্সটারন_ডিএলএল_এক্সপোর্ট == বহিরাগত "সি "____ ডেস্কলস্পেক (dllexport)? এটি কি এসডিকে আছে?
আর্দভার্ক

3
প্রকল্পের লিঙ্কার সেটিংসে মডিউল সংজ্ঞা ফাইল যুক্ত করতে ভুলবেন না - কেবল "প্রকল্পে একটি বিদ্যমান আইটেম যুক্ত করা" যথেষ্ট নয়!
জিমি

1
আমি এটি ভিএস সহ একটি ডিএলএল সংকলন করতে ব্যবহার করেছি এবং তারপরে .C ব্যবহার করে আর থেকে কল করব। গ্রেট!
জুয়াসান্ট্রো

33

সি ++ এর জন্য:

আমি কেবল একই সমস্যার মুখোমুখি হয়েছি এবং আমি মনে করি যে এটি সমস্যা উল্লেখ করার মতো, যখন কেউ উভয় __stdcall(বা WINAPI) এবং extern "C" :

আপনি জানেন extern "C"যে সাজসজ্জাটি সরান যাতে পরিবর্তে:

__declspec(dllexport) int Test(void)                        --> dumpbin : ?Test@@YaHXZ

আপনি একটি প্রতীক নাম অদক্ষিত প্রাপ্ত:

extern "C" __declspec(dllexport) int Test(void)             --> dumpbin : Test

তবে _stdcall (= ম্যাক্রো উইনাপি, যা কলিং কনভেনশন পরিবর্তন করে) নামগুলিও সজ্জিত করে যাতে আমরা যদি উভয়কেই ব্যবহার করি তবে:

   extern "C" __declspec(dllexport) int WINAPI Test(void)   --> dumpbin : _Test@0

এবং এর সুবিধা extern "C" হারিয়ে গেছে কারণ প্রতীকটি সাজানো হয়েছে (_ @ বাইটস সহ)

নোট করুন যে এটি কেবল x86 আর্কিটেকচারের জন্যই ঘটে কারণ __stdcallকনভেনশনটি x64 এ উপেক্ষা করা হয়েছে ( এমএসডিএন : x64 আর্কিটেকচারে, কনভেনশন অনুসারে, আর্গুমেন্টগুলি সম্ভব হলে রেজিস্টারে পাস করা হয়, এবং পরবর্তী যুক্তিগুলি স্ট্যাকের মধ্যে পাস করা হয় ।)

আপনি যদি x86 এবং x64 উভয় প্ল্যাটফর্মকে লক্ষ্য করে থাকেন তবে এটি বিশেষত জটিল।


দুটি সমাধান

  1. একটি সংজ্ঞা ফাইল ব্যবহার করুন। তবে এটি আপনাকে ডিএফ ফাইলের অবস্থা বজায় রাখতে বাধ্য করে।

  2. সহজতম উপায়: ম্যাক্রো সংজ্ঞায়িত করুন ( এমএসডিএন দেখুন ):

# নির্দিষ্ট রফতানি মন্তব্য (লিঙ্কার, "/ রফতানি:" __FUNCTION__ "=" __FUNCDNAME__)

এবং তারপরে ফাংশন বডিটিতে নিম্নলিখিত প্রগমা অন্তর্ভুক্ত করুন:

#pragma EXPORT

সম্পূর্ণ উদাহরণ:

 int WINAPI Test(void)
{
    #pragma EXPORT
    return 1;
}

এটি x86 এর __stdcallজন্য কনভেনশনটি সংরক্ষণের সময় x86 এবং x64 উভয় লক্ষ্যগুলির জন্য অজস্র ফাংশনটি রফতানি করবে । __declspec(dllexport) নয় এই ক্ষেত্রে প্রয়োজন।


5
এই গুরুত্বপূর্ণ ইঙ্গিতটির জন্য আপনাকে ধন্যবাদ। আমি ইতিমধ্যে ভেবে দেখেছি কেন আমার B৪ বিট ডিএলএল 32 বিট থেকে আলাদা? আমি উত্তর হিসাবে গ্রহণযোগ্য উত্তর চেয়ে আপনার উত্তর অনেক বেশি দরকারী।
এলমু

1
আমি সত্যিই এই পদ্ধতির পছন্দ। আমার একমাত্র সুপারিশটি হ'ল ম্যাক্রোর নতুন নামকরণকে এক্সপোর্ট_ফুনশনেকরণ করা হবে কারণ __FUNCTION__ম্যাক্রো কেবল ফাংশনে কাজ করে।
লুইস

3

আমার ঠিক একই সমস্যা ছিল, আমার সমাধানটি ছিল __declspec(dllexport)রফতানি ( http://msdn.microsoft.com/en-us/library/d91k01sh.aspx ) সংজ্ঞায়নের পরিবর্তে মডিউল সংজ্ঞা ফাইল (.def) ব্যবহার করা । এটি কেন কাজ করে তা আমার কোনও ধারণা নেই তবে এটি কাজ করে


অন্য কারও কাছে এটি নোট করুন: .defমডিউল রফতানি ফাইল ব্যবহার করে কাজ হয় তবে externউদাহরণস্বরূপ গ্লোবাল ডেটা-র ক্ষেত্রে শিরোনাম ফাইলে সংজ্ঞা সরবরাহ করতে সক্ষম হওয়া ব্যয় করে , আপনাকে অভ্যন্তরীণ ব্যবহারের জন্য externম্যানুয়ালি সংজ্ঞা সরবরাহ করতে হবে যে তথ্য। (হ্যাঁ, আপনার প্রয়োজন হয় এমন সময়গুলিও থাকে)) সাধারণত এবং বিশেষত ক্রস-প্ল্যাটফর্ম কোডের জন্য ম্যাক্রোর সাথে ব্যবহার করা ভাল so যাতে আপনি সাধারণভাবে ডেটা হ্যান্ড করতে পারেন। __declspec()
ক্রিস ক্রিচো

2
কারণ সম্ভবত কারণ যদি আপনি ব্যবহার করছেন হয় __stdcall, তারপর __declspec(dllexport)হবে না সজ্জা মুছে ফেলুন। .defতবে একটি উইলে ফাংশন যুক্ত করা ।
বিজন লিন্ডকভিস্ট

1
@ BjörnLindqvist +1, নোট করুন যে এটি কেবলমাত্র x86 এর ক্ষেত্রে। আমার উত্তর দেখুন।
ম্যালিক

-1

আমি মনে করি _নং আপনি যা চান তা পেতে পারে তবে এটি সংক্ষেপকটি ফাংশনের জন্য স্ট্যাক ম্যানেজমেন্ট কোড উত্পন্ন করতে বাধা দেয়। বাহ্যিক "সি" সি স্টাইল নাম সজ্জা কারণ। এটি সরান এবং এটি আপনার _ এর থেকে মুক্তি পাওয়া উচিত। সংযোগকারী আন্ডারস্কোর যোগ করে না, সংকলকটি করে। stdcall আর্গুমেন্ট স্ট্যাকের আকার যুক্ত হওয়ার কারণ ঘটায়।

আরও তথ্যের জন্য, দেখুন: http://en.wikedia.org/wiki/X86_calling_conventions http://www.codeproject.com/KB/cpp/calling_conventions_demysified.aspx

বড় প্রশ্ন আপনি কেন এটি করতে চান? ম্যাংলেড নাম গুলোতে কী দোষ?


মাঙ্গলযুক্ত নামগুলি যখন লোডলিবারি / গেটপ্রোকএড্রেস বা অন্যান্য পদ্ধতিগুলি ব্যবহার করে যা এসি / সি ++ শিরোনামের উপর নির্ভর করে না তখন কুশ্রী হয়।
আর্দভার্ক

4
এটি অপ্রয়োজনীয় হবে - আপনি কেবল খুব বিশেষায়িত পরিস্থিতিতে কম্পাইলার উত্পন্ন স্ট্যাক ম্যানেজমেন্ট কোডটি সরাতে চান। (কেবলমাত্র __cdecl ব্যবহার করা সজ্জা হারাতে কম ক্ষতিকারক উপায় হবে - ডিফল্টরূপে __declspec (dllexport) __cdecl পদ্ধতিতে সাধারণ _ উপসর্গ অন্তর্ভুক্ত বলে মনে হয় না))
ইয়ান গ্রিফিথস

আমি সত্যিই বলছিলাম না যে এটি সহায়ক হবে, সুতরাং অন্যান্য প্রভাব সম্পর্কে আমার সতর্কতা এবং তিনি কেন এটি করতে চেয়েছিলেন তা প্রশ্ন করে।
রব কে
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.