এই প্রশ্নের সংক্ষিপ্ত উত্তর না । যেহেতু কোনও স্ট্যান্ডার্ড সি ++ এবিআই নেই (অ্যাপ্লিকেশন বাইনারি ইন্টারফেস, কনভেনশনগুলি কল করার জন্য একটি স্ট্যান্ডার্ড, ডেটা প্যাকিং / প্রান্তিককরণ, ধরণের আকার ইত্যাদি), আপনাকে ক্লাসের সাথে আচরণের একটি স্ট্যান্ডার্ড পদ্ধতিতে চেষ্টা করতে এবং প্রয়োগ করতে অনেক হুপ করতে হবে আপনার প্রোগ্রামে বস্তু। এই সমস্ত হুপের মধ্য দিয়ে লাফিয়ে ওঠার পরেও এটি কাজ করবে এমন কোনও গ্যারান্টিও নেই, বা কোনও গ্যারান্টি নেই যে একটি সংকলক রিলিজে কাজ করে এমন একটি সমাধান পরবর্তী ক্ষেত্রে কাজ করবে।
কেবল এটিকে ব্যবহার করে একটি সরল সি ইন্টারফেস তৈরি করুন extern "C"
, যেহেতু সি এবিআই সুস্পষ্টভাবে সংজ্ঞায়িত এবং স্থিতিশীল।
আপনি যদি সত্যই সত্যই ডিএলএল সীমানা জুড়ে সি ++ অবজেক্টগুলি পাস করতে চান তবে এটি প্রযুক্তিগতভাবে সম্ভব। আপনাকে যে কয়েকটি কারণের জন্য অ্যাকাউন্ট করতে হবে তা এখানে রয়েছে:
ডেটা প্যাকিং / প্রান্তিককরণ
প্রদত্ত শ্রেণীর মধ্যে, পৃথক ডেটা সদস্যদের সাধারণত মেমরিতে বিশেষভাবে রাখা হবে যাতে তাদের ঠিকানাগুলি ধরণের আকারের একাধিকের সাথে মিলে যায়। উদাহরণস্বরূপ, int
একটি 4-বাইট সীমানায় সংযুক্ত করা যেতে পারে।
যদি আপনার ডিএলএলটি আপনার এএসইএর চেয়ে আলাদা সংকলক দিয়ে সংকলিত হয় তবে প্রদত্ত শ্রেণীর ডিএলএল সংস্করণে এক্সই এর সংস্করণের চেয়ে আলাদা প্যাকিং থাকতে পারে, সুতরাং যখন EXE ক্লাস অবজেক্টটি ডিএলএলে পাস করে, তখন ডিএলএল একটি সঠিকভাবে অ্যাক্সেস করতে অক্ষম হতে পারে শ্রেণীর মধ্যে দেওয়া ডেটা মেম্বার ডিএলএল শ্রেণীর নিজস্ব সংজ্ঞা দ্বারা নির্দিষ্ট ঠিকানাটি পড়ার চেষ্টা করবে, EXE- এর সংজ্ঞা নয়, এবং যেহেতু পছন্দসই ডেটা সদস্য সেখানে সংরক্ষণ করা হয়নি, ফলে আবর্জনার মানগুলির ফলাফল হবে।
আপনি #pragma pack
প্রিপ্রোসেসর নির্দেশিকা ব্যবহার করে এটি ঘিরে কাজ করতে পারেন , যা সংকলককে নির্দিষ্ট প্যাকিং প্রয়োগ করতে বাধ্য করবে। আপনি যদি সংকলকটি বেছে নিয়েছে তার চেয়ে বড় প্যাক মান নির্বাচন করে সংকলকটি এখনও ডিফল্ট প্যাকিং প্রয়োগ করবে , সুতরাং আপনি যদি একটি বৃহত প্যাকিংয়ের মান চয়ন করেন তবে একটি শ্রেণীর এখনও সংকলকগুলির মধ্যে পৃথক প্যাকিং থাকতে পারে। এর সমাধানটি হ'ল ব্যবহার করা #pragma pack(1)
, যা সংকলককে ডেটা সদস্যদের এক বাইট সীমানায় সারিবদ্ধ করতে বাধ্য করবে (মূলত, কোনও প্যাকিং প্রয়োগ করা হবে না)। এটি দুর্দান্ত ধারণা নয়, কারণ এটি কার্যকারিতা সংক্রান্ত সমস্যা বা নির্দিষ্ট সিস্টেমে ক্রাশও করতে পারে। তবে এটি আপনার শ্রেণীর ডেটা সদস্যদের মেমরিতে একত্রিত হওয়ার সাথে সামঞ্জস্যতা নিশ্চিত করবে ।
সদস্য পুনর্নির্মাণ
আপনার বর্গ না হয়, তাহলে মান-বিন্যাস , কম্পাইলার মেমরি, তার ডেটা সদস্যদের নতুন করে সাজানো পারেন । এটি কীভাবে হয় তার কোনও মান নেই, সুতরাং কোনও ডেটা পুনরায় সাজানো কম্পাইলারগুলির মধ্যে অসঙ্গতি সৃষ্টি করতে পারে। একটি ডিএলএল এর পিছনে পিছনে ডেটা পাস করার জন্য স্ট্যান্ডার্ড-লেআউট ক্লাসগুলির প্রয়োজন হবে।
আহ্বান সম্মেলন
একটি প্রদত্ত ফাংশন থাকতে পারে এমন একাধিক কলিং কনভেনশন রয়েছে। এই কলিং কনভেনশনগুলি ডেটা ফাংশনে কীভাবে প্রেরণ করা হবে তা নির্দিষ্ট করে: প্যারামিটারগুলি কি রেজিস্টারগুলিতে বা স্ট্যাকের মধ্যে সঞ্চিত থাকে? কী অর্ডার স্ট্যাকের উপর চাপানো হয়? ফাংশন শেষ হওয়ার পরে স্ট্যাকের মধ্যে থাকা কোন যুক্তি পরিষ্কার করেন?
এটি গুরুত্বপূর্ণ যে আপনি একটি স্ট্যান্ডার্ড কলিং কনভেনশন বজায় রাখুন; যদি আপনি কোনও ফাংশন _cdecl
সি ++ এর জন্য ডিফল্ট হিসাবে ঘোষণা করেন এবং _stdcall
খারাপ জিনিসগুলি ব্যবহার করে এটি কল করার চেষ্টা করবেন । _cdecl
তবে সি ++ ফাংশনগুলির জন্য ডিফল্ট কলিং কনভেনশন হ'ল, সুতরাং এটি এমন একটি জিনিস যা আপনি ইচ্ছাকৃতভাবে একটি _stdcall
জায়গায় এবং _cdecl
অন্য কোনও স্থানে নির্দিষ্ট করে ভেঙে না ফেললে তা ভাঙবে না ।
ডেটাটাইপ আকার
এই ডকুমেন্টেশন অনুসারে , উইন্ডোজে, আপনার অ্যাপ্লিকেশন 32-বিট বা 64-বিট কিনা তা নির্বিশেষে বেশিরভাগ মৌলিক ডেটাটাইপগুলির আকার একই আকার থাকে have যাইহোক, প্রদত্ত ডেটাটাইপের আকার যেহেতু সংকলক দ্বারা প্রয়োগ করা হয়, কোনও মানক দ্বারা নয় (সমস্ত মানক গ্যারান্টি হ'ল 1 == sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long)
), সম্ভব যেখানে সম্ভব ডেটাটাইপ আকারের সামঞ্জস্যতা নিশ্চিত করতে স্থির-আকারের ডেটাটাইপগুলি ব্যবহার করা ভাল ধারণা ।
গাদা ইস্যু
যদি আপনার ডিএলএল আপনার EXE এর তুলনায় সি রানটাইমের ভিন্ন সংস্করণে লিঙ্ক করে তবে দুটি মডিউল আলাদা হ্যাপ ব্যবহার করবে । মডিউলগুলি বিভিন্ন সংকলকগুলির সাথে সংকলিত হচ্ছে এটি প্রদত্ত একটি বিশেষত সমস্যা।
এটি প্রশমিত করতে, সমস্ত মেমরি ভাগ করা হিপগুলিতে বরাদ্দ করতে হবে এবং একই গাদা থেকে বিচ্ছিন্ন করতে হবে। সৌভাগ্যক্রমে, উইন্ডোজ এটিকে সাহায্যের জন্য এপিআই সরবরাহ করে: গেটপ্রসেসহীপ আপনাকে হোস্টের এক্সইএইপি'র হিপ অ্যাক্সেস করতে দেবে এবং হিপএলোক / হিপফ্রি আপনাকে এই স্তূপের মধ্যে বরাদ্দ করতে এবং ফ্রি মেমরি দেয়। এটি গুরুত্বপূর্ণ যে আপনি স্বাভাবিক ব্যবহার করবেন না malloc
/ free
কারণ কোনও গ্যারান্টি নেই যে তারা আপনার প্রত্যাশা অনুযায়ী কাজ করবে।
এসটিএল ইস্যু
সি ++ স্ট্যান্ডার্ড লাইব্রেরিতে এবিআই ইস্যুগুলির নিজস্ব সেট রয়েছে। নেই কোন গ্যারান্টি যে একটি প্রদত্ত STL টাইপ আউট মেমরি একই ভাবে পাড়া হল কিংবা এখানে একটি গ্যারান্টি একটি প্রদত্ত STL বর্গ অন্য এক বাস্তবায়ন থেকে একই আকার আছে (বিশেষ করে, ডিবাগ তৈরী করে একটি মধ্যে অতিরিক্ত ডিবাগ তথ্য করা হতে পারে প্রদত্ত এসটিএল প্রকার)। অতএব, যে কোনও এসটিএল ধারককে ডিএলএল সীমানা পেরোনোর আগে এবং অন্যদিকে পুনরায় প্যাক করার আগে মৌলিক ধরণের প্যাকগুলি আনতে হবে।
নাম ম্যাঙ্গালিং
আপনার ডিএলএল সম্ভবত পূর্বনির্ধারিত ফাংশনগুলি রফতানি করবে যা আপনার EXE কল করতে চাইবে। যাইহোক, সি ++ সংকলকগুলির ফাংশন নামগুলির ম্যাঙ্গলিংয়ের মানক উপায় নেই । এই নাম দেওয়া একটি ফাংশন মানে GetCCDLL
করতে mangled করা যেতে পারে _Z8GetCCDLLv
জিসিসি এবং ?GetCCDLL@@YAPAUCCDLL_v1@@XZ
MSVC হবে।
আপনি ইতিমধ্যে আপনার ডিএলএল সাথে স্থিতিশীল সংযোগের গ্যারান্টি দিতে সক্ষম হবেন না, যেহেতু জিসিসির সাথে উত্পাদিত কোনও ডিএলএল একটি .lib ফাইল তৈরি করতে পারে না এবং এমএসভিসিতে কোনও ডিএলএলকে স্ট্যাটিকভাবে সংযুক্ত করার জন্য একটি প্রয়োজন। ডায়নামিকভাবে লিঙ্কিং অনেকটা ক্লিনার বিকল্পের মতো মনে হয় তবে নাম ম্যাংলিংটি আপনার পথে আসে: আপনি যদি GetProcAddress
ভুল ম্যাংলেড নামের চেষ্টা করেন , কলটি ব্যর্থ হবে এবং আপনি আপনার ডিএলএল ব্যবহার করতে পারবেন না। এটিকে ঘুরে দেখার জন্য সামান্য কিছু হ্যাকারি প্রয়োজন এবং এটি একটি ডিএলএল সীমানা পেরিয়ে সি ++ ক্লাস পাস করা মোটামুটি একটি বড় কারণ bad
আপনাকে আপনার ডিএলএল তৈরি করতে হবে, তারপরে উত্পাদিত .ডিএফ ফাইল পরীক্ষা করতে হবে (যদি একটি উত্পন্ন হয়; এটি আপনার প্রকল্পের বিকল্পগুলির উপর ভিত্তি করে পরিবর্তিত হবে) বা ম্যাংডেড নামটি খুঁজে পেতে নির্ভরতা ওয়াকারের মতো একটি সরঞ্জাম ব্যবহার করুন। তারপরে, আপনাকে ম্যাংলেড ফাংশনটিতে একটি নিরবিচ্ছিন্ন ওরফে সংজ্ঞা দিয়ে আপনার নিজের .def ফাইলটি লিখতে হবে। উদাহরণস্বরূপ, আসুন GetCCDLL
আমি আরও কিছুটা উপরে উল্লিখিত ফাংশনটি ব্যবহার করি। আমার সিস্টেমে, নিম্নলিখিত .def ফাইলগুলি যথাক্রমে জিসিসি এবং এমএসভিসির জন্য কাজ করে:
জিসিসি:
EXPORTS
GetCCDLL=_Z8GetCCDLLv @1
MSVC:
EXPORTS
GetCCDLL=?GetCCDLL@@YAPAUCCDLL_v1@@XZ @1
আপনার ডিএলএল পুনর্নির্মাণ করুন, তারপরে এটি রফতানি করে ফাংশনগুলি আবার পরীক্ষা করুন। একটি নিরবিচ্ছিন্ন ফাংশন নাম তাদের মধ্যে থাকা উচিত। মনে রাখবেন যে আপনি ওভারলোডেড ফাংশনগুলি এইভাবে ব্যবহার করতে পারবেন না : ম্যামলেগড নাম দ্বারা সংজ্ঞায়িত অনুসারে আনম্যাংড ফাংশন নামটি একটি নির্দিষ্ট ফাংশন ওভারলোডের একটি নাম alias এছাড়াও মনে রাখবেন যে প্রতিবার আপনি ফাংশন ঘোষণাগুলি পরিবর্তন করার সময় আপনার ডিএলএলটির জন্য একটি নতুন .def ফাইল তৈরি করতে হবে, কারণ মাংযুক্ত নামগুলি পরিবর্তন হবে। সর্বাধিক গুরুত্বপূর্ণভাবে, নাম ম্যাংলিংকে বাইপাস করে আপনি লিঙ্কারটি যে কোনও সুরক্ষা ওভারাইড করছেন যা আপনাকে বেমানান ইস্যুতে অফার করার চেষ্টা করছে।
আপনি যদি আপনার ডিএলএল অনুসরণ করার জন্য একটি ইন্টারফেস তৈরি করেন তবে এই পুরো প্রক্রিয়াটি সহজ since তবে, একই সতর্কতা এখনও প্রযোজ্য।
কোনও ফাংশনে ক্লাস অবজেক্টগুলি পাস করা
ক্রস-সংকলক ডেটা পাস করার সমস্যাগুলিতে এটি সম্ভবত সবচেয়ে সূক্ষ্ম এবং সবচেয়ে বিপজ্জনক। এমনকি আপনি যদি সমস্ত কিছু পরিচালনা করেন তবে কোনও কার্যক্রমে কীভাবে আর্গুমেন্ট সরবরাহ করা হয় তার কোনও মান নেই । এটি কোনও আপাত কারণ এবং তাদের ডিবাগ করার সহজ কোনও উপায় ছাড়াই সূক্ষ্ম ক্র্যাশ ঘটাতে পারে । আপনাকে কোনও রিটার্ন মানগুলির জন্য বাফার সহ পয়েন্টারগুলির মাধ্যমে সমস্ত যুক্তিগুলি পাস করতে হবে । এটি আনাড়ি এবং অসুবিধাগুলি এবং এটি অন্য একটি হ্যাকি ওয়ার্কআউন্ড যা কাজ করতে পারে বা নাও পারে।
এই সমস্ত কর্মক্ষেত্রকে একত্রিত করে এবং টেম্পলেট এবং অপারেটরগুলির সাথে কিছু সৃজনশীল কাজের উপর ভিত্তি করে , আমরা নিরাপদে কোনও ডিএলএল সীমানা পেরিয়ে অবজেক্টগুলি পাস করার চেষ্টা করতে পারি। মনে রাখবেন যে সি ++ 11 সমর্থন বাধ্যতামূলক, যেমন সমর্থন #pragma pack
এবং এর রূপগুলি; এমসভিসি 2013 জিসিসি এবং বিড়ম্বনার সাম্প্রতিক সংস্করণগুলির মতো এই সমর্থনটি সরবরাহ করে।
//POD_base.h: defines a template base class that wraps and unwraps data types for safe passing across compiler boundaries
//define malloc/free replacements to make use of Windows heap APIs
namespace pod_helpers
{
void* pod_malloc(size_t size)
{
HANDLE heapHandle = GetProcessHeap();
HANDLE storageHandle = nullptr;
if (heapHandle == nullptr)
{
return nullptr;
}
storageHandle = HeapAlloc(heapHandle, 0, size);
return storageHandle;
}
void pod_free(void* ptr)
{
HANDLE heapHandle = GetProcessHeap();
if (heapHandle == nullptr)
{
return;
}
if (ptr == nullptr)
{
return;
}
HeapFree(heapHandle, 0, ptr);
}
}
//define a template base class. We'll specialize this class for each datatype we want to pass across compiler boundaries.
#pragma pack(push, 1)
// All members are protected, because the class *must* be specialized
// for each type
template<typename T>
class pod
{
protected:
pod();
pod(const T& value);
pod(const pod& copy);
~pod();
pod<T>& operator=(pod<T> value);
operator T() const;
T get() const;
void swap(pod<T>& first, pod<T>& second);
};
#pragma pack(pop)
//POD_basic_types.h: holds pod specializations for basic datatypes.
#pragma pack(push, 1)
template<>
class pod<unsigned int>
{
//these are a couple of convenience typedefs that make the class easier to specialize and understand, since the behind-the-scenes logic is almost entirely the same except for the underlying datatypes in each specialization.
typedef int original_type;
typedef std::int32_t safe_type;
public:
pod() : data(nullptr) {}
pod(const original_type& value)
{
set_from(value);
}
pod(const pod<original_type>& copyVal)
{
original_type copyData = copyVal.get();
set_from(copyData);
}
~pod()
{
release();
}
pod<original_type>& operator=(pod<original_type> value)
{
swap(*this, value);
return *this;
}
operator original_type() const
{
return get();
}
protected:
safe_type* data;
original_type get() const
{
original_type result;
result = static_cast<original_type>(*data);
return result;
}
void set_from(const original_type& value)
{
data = reinterpret_cast<safe_type*>(pod_helpers::pod_malloc(sizeof(safe_type))); //note the pod_malloc call here - we want our memory buffer to go in the process heap, not the possibly-isolated DLL heap.
if (data == nullptr)
{
return;
}
new(data) safe_type (value);
}
void release()
{
if (data)
{
pod_helpers::pod_free(data); //pod_free to go with the pod_malloc.
data = nullptr;
}
}
void swap(pod<original_type>& first, pod<original_type>& second)
{
using std::swap;
swap(first.data, second.data);
}
};
#pragma pack(pop)
pod
বর্গ, যে মৌলিক ডাটাটাইপ জন্য বিশেষ যাতে হয় int
স্বয়ংক্রিয়ভাবে আবৃত করা হবে int32_t
, uint
সম্পৃক্ত রয়েছে হবে uint32_t
, ইত্যাদি এই সব লোকচক্ষুর অন্তরালে ঘটে, ওভারলোড ধন্যবাদ =
এবং ()
অপারেটর। আমি অন্তর্ভুক্ত ডেটাটাইপগুলি বাদে প্রায় সম্পূর্ণ একইরকম বেসিক টাইপ স্পেশালাইজেশন বাদ দিয়েছি (স্পেশালাইজেশনটিতে bool
কিছুটা অতিরিক্ত যুক্তি রয়েছে, যেহেতু এটি একটিতে রূপান্তরিত হয় int8_t
এবং তারপরে int8_t
আবার রূপান্তর করতে 0 এর সাথে তুলনা করা হয় bool
, তবে এটি মোটামুটি তুচ্ছ)।
আমরা এসটিএল প্রকারগুলিও এইভাবে মোড়াতে পারি, যদিও এটির জন্য কিছুটা অতিরিক্ত কাজ প্রয়োজন:
#pragma pack(push, 1)
template<typename charT>
class pod<std::basic_string<charT>> //double template ftw. We're specializing pod for std::basic_string, but we're making this specialization able to be specialized for different types; this way we can support all the basic_string types without needing to create four specializations of pod.
{
//more comfort typedefs
typedef std::basic_string<charT> original_type;
typedef charT safe_type;
public:
pod() : data(nullptr) {}
pod(const original_type& value)
{
set_from(value);
}
pod(const charT* charValue)
{
original_type temp(charValue);
set_from(temp);
}
pod(const pod<original_type>& copyVal)
{
original_type copyData = copyVal.get();
set_from(copyData);
}
~pod()
{
release();
}
pod<original_type>& operator=(pod<original_type> value)
{
swap(*this, value);
return *this;
}
operator original_type() const
{
return get();
}
protected:
//this is almost the same as a basic type specialization, but we have to keep track of the number of elements being stored within the basic_string as well as the elements themselves.
safe_type* data;
typename original_type::size_type dataSize;
original_type get() const
{
original_type result;
result.reserve(dataSize);
std::copy(data, data + dataSize, std::back_inserter(result));
return result;
}
void set_from(const original_type& value)
{
dataSize = value.size();
data = reinterpret_cast<safe_type*>(pod_helpers::pod_malloc(sizeof(safe_type) * dataSize));
if (data == nullptr)
{
return;
}
//figure out where the data to copy starts and stops, then loop through the basic_string and copy each element to our buffer.
safe_type* dataIterPtr = data;
safe_type* dataEndPtr = data + dataSize;
typename original_type::const_iterator iter = value.begin();
for (; dataIterPtr != dataEndPtr;)
{
new(dataIterPtr++) safe_type(*iter++);
}
}
void release()
{
if (data)
{
pod_helpers::pod_free(data);
data = nullptr;
dataSize = 0;
}
}
void swap(pod<original_type>& first, pod<original_type>& second)
{
using std::swap;
swap(first.data, second.data);
swap(first.dataSize, second.dataSize);
}
};
#pragma pack(pop)
এখন আমরা একটি ডিএলএল তৈরি করতে পারি যা এই পড ধরণের ব্যবহার করে। প্রথমে আমাদের একটি ইন্টারফেস দরকার, তাই ম্যাংলিং বের করার জন্য আমাদের কাছে কেবল একটি পদ্ধতি থাকবে।
//CCDLL.h: defines a DLL interface for a pod-based DLL
struct CCDLL_v1
{
virtual void ShowMessage(const pod<std::wstring>* message) = 0;
};
CCDLL_v1* GetCCDLL();
এটি কেবলমাত্র ডিএলএল এবং যে কোনও কলার ব্যবহার করতে পারে উভয়ই একটি প্রাথমিক ইন্টারফেস তৈরি করে। মনে রাখবেন যে আমরা একটিতে একটি পয়েন্টার দিয়ে যাচ্ছি pod
, pod
নিজেই নয়। এখন আমাদের এটি ডিএলএল পক্ষের প্রয়োগ করা দরকার:
struct CCDLL_v1_implementation: CCDLL_v1
{
virtual void ShowMessage(const pod<std::wstring>* message) override;
};
CCDLL_v1* GetCCDLL()
{
static CCDLL_v1_implementation* CCDLL = nullptr;
if (!CCDLL)
{
CCDLL = new CCDLL_v1_implementation;
}
return CCDLL;
}
এবং এখন ShowMessage
ফাংশন বাস্তবায়ন করা যাক :
#include "CCDLL_implementation.h"
void CCDLL_v1_implementation::ShowMessage(const pod<std::wstring>* message)
{
std::wstring workingMessage = *message;
MessageBox(NULL, workingMessage.c_str(), TEXT("This is a cross-compiler message"), MB_OK);
}
খুব বেশি অভিনব কিছু নয়: এটি কেবল পাস pod
করা wstring
একটি সাধারণকে অনুলিপি করে এবং এটি একটি বার্তা বাক্সে দেখায়। সর্বোপরি, এটি কেবল একটি পোক , সম্পূর্ণ ইউটিলিটি লাইব্রেরি নয়।
এখন আমরা ডিএলএল তৈরি করতে পারি। লিঙ্কারের নামের ম্যাঙ্গলিংয়ের চারপাশে কাজ করার জন্য বিশেষ .def ফাইলগুলি ভুলে যাবেন না। (দ্রষ্টব্য: আমি যে সিসিডিএলএল স্ট্রাক্টটি তৈরি করেছি তা এখানে উপস্থিত আমি তার চেয়ে বেশি ফাংশন রেখেছি। .ডিফ ফাইলগুলি প্রত্যাশার মতো কাজ করতে পারে না))
এখন কোনও এক্সই এর জন্য ডিএলএল কল করুন:
//main.cpp
#include "../CCDLL/CCDLL.h"
typedef CCDLL_v1*(__cdecl* fnGetCCDLL)();
static fnGetCCDLL Ptr_GetCCDLL = NULL;
int main()
{
HMODULE ccdll = LoadLibrary(TEXT("D:\\Programming\\C++\\CCDLL\\Debug_VS\\CCDLL.dll")); //I built the DLL with Visual Studio and the EXE with GCC. Your paths may vary.
Ptr_GetCCDLL = (fnGetCCDLL)GetProcAddress(ccdll, (LPCSTR)"GetCCDLL");
CCDLL_v1* CCDLL_lib;
CCDLL_lib = Ptr_GetCCDLL(); //This calls the DLL's GetCCDLL method, which is an alias to the mangled function. By dynamically loading the DLL like this, we're completely bypassing the name mangling, exactly as expected.
pod<std::wstring> message = TEXT("Hello world!");
CCDLL_lib->ShowMessage(&message);
FreeLibrary(ccdll); //unload the library when we're done with it
return 0;
}
এবং ফলাফল এখানে। আমাদের ডিএলএল কাজ করে। আমরা অতীতের এসটিএল এবিআই ইস্যুগুলি, বিগত সি ++ এবিআইয়ের সমস্যাগুলি, অতীত ম্যাংলিংয়ের সমস্যাগুলিতে সাফল্যের সাথে পৌঁছেছি এবং আমাদের এমএসভিসি ডিএলএল একটি জিসিসি এক্সি নিয়ে কাজ করছে।
উপসংহারে, যদি আপনাকে অবশ্যই ডিএলএল সীমানা জুড়ে অবশ্যই সি ++ অবজেক্টগুলি পাস করতে হয় তবে আপনি এটি এটি করেন। যাইহোক, এর কোনওটিই আপনার সেটআপ বা অন্য কারও সাথে কাজ করার গ্যারান্টিযুক্ত নয়। এর যে কোনও সময় যে কোনও সময় ভেঙে যেতে পারে এবং সম্ভবত আপনার সফ্টওয়্যারটির একটি বড় প্রকাশের সময় নির্ধারিত হওয়ার আগের দিনটি ভেঙ্গে যাবে। এই পথটি হ্যাক, ঝুঁকি এবং সাধারণ বুদ্ধি দিয়ে পূর্ণ যা সম্ভবত আমার জন্যই গুলি করা উচিত। আপনি যদি এই রুটে যান তবে চরম সতর্কতার সাথে পরীক্ষা করুন। এবং সত্যই ... কেবল এটি কিছু করবেন না।