PDA

View Full Version : سوال: ساختن پروژه dll در MFC



mesgar
جمعه 17 آبان 1387, 00:19 صبح
سلام
من پروژه dll مي خوام تو MFC ويژوال استوديو 2005 بسازم وقتي اسم پروژه رو تعيين مي كنم مي رسم به پنجره اي به شكل زير :
http://mesgar.persiangig.ir/mfc.JPG
حالا مي خواستم بدونم كدوم گزينه ها رو بايد انتخاب كنم
اولا تو همين dll از يك dll به زبان سي پلاس پلاس مي خوام استفاده كنم
و در نهايت از dll نهايي در يك پروژه سي شارپ مي خوام استفاده كنم
حالا مي خواستم بدونم كدوم گزينه ها رو بايد انتخاب كنم و كدوم رو نه
راستش من يكيش رو انتخاب كردم و dll رو هم ساختم ولي موقع استفاده در برنامه مورد نظر به مشكل برخورد كردم
كد زير كد برنامه ام در سي شارپ هست


[DllImport("c:\\temp.dll", EntryPoint = "GetValidity")]
public static extern bool GetValidity();
public Form1()
{
InitializeComponent();
MessageBox.Show(GetValidity()+"");
MessageBox.Show("ok");
}


و اينم اروري كه هنگام اجرا داده مي شود :

Unable to load DLL 'c:\\temp.dll': The specified procedure could not be found. (Exception from HRESULT: 0x8007007F)
البته مي دونم ميگه تابع رو پيدا نكردم ولي وقتي dll رو ميدم به برنامه anywhere PE viewer تابع رو به عنوان تابع اكسپورت شده نشون ميده
حالا دوستان مي تونن كمك كنند و بگن كجاي كار من اشتباه بوده ؟!!!
ممنون

Nima_NF
جمعه 17 آبان 1387, 00:54 صبح
شما برای کارتان همان حالت shared MFC DLL را انتخاب کنید،
در حالت statically linked حجم برنامه افزایش پیدا می کند اما دیگر نیازی به انتشار dll نیست، اما در کل static برای نرم افزارها پیشنهاد نمی شود، مخصوصا وقتی می خواهید با #C کار کنید.
سومین مورد هم که فقط برای برنامه های MFC هست.

بدون کدهای dll نمی توان نظر داد که چرا خطای load دریافت می کنید، صدها دلیل وجود دارد و ممکن است در جایی از کدها اشتباه کرده باشید.
با نرم افزار dependency (یا همان depends) همراه VC، آن را چک کنید تا ببینید که تابع مورد نظر شما با همان نام export شده باشد، حرف @ و غیره نداشته باشد.

ضمنا تستی کنید، dll را در system32 ویندوز کپی کنید و فقط نام آن را در پارامتر اول DllImport در #C (بدون \\:c )به کار ببرید.

mesgar
جمعه 17 آبان 1387, 11:15 صبح
ممنون از پاسختون
من الان تونستم dll رو بسازم و از dll هم استفاده كردم ولي يه مشكل جديد بوجود اومد
كد زير كد قسمتي از dll مي باشد


char* GetName()
{
TCHAR path[1000];
GetModuleFileName(NULL,path,1000);
int index_start=0;
int index_end=0;
for(int i=0;i<1000;i++)
{
if(path[i]!='\0')
index_end=i;
if(path[i]=='\\')
index_start=i;
}
char* name=new char[index_end-index_start+1];
for(int i=0;i<1000;i++)
{
name[i]=(char)path[i+ index_start+1];
}
name[index_end-index_start]='\0';
return name;
}
extern "C" {
__declspec(dllexport) extern bool GetValidity ();
}
extern bool GetValidity()
{
char* name=GetName();
bool valid=false;
if(strcmp(name,"test_dll.exe")==0) valid= true;
if(strcmp(name,"test_dll.vshost.exe")==0) valid= true;
return valid;
}

حالا وقتي كد زير را در برنامه سي شارپ مي نويسم :


[DllImport("temp.dll", EntryPoint = "GetValidity")]
public static extern bool GetValidity();
public Form1()
{
InitializeComponent();
MessageBox.Show(GetValidity() + "");
}

و برنامه رو اجرا مي كنم و پيغام هم نمايش داده ميشه ولي در كسري از ثانيه پيغام بسته ميشه و برنامه تموم ميشه و ادامه برنامه اجرا نميشه
در ضمن تست كردم و ديدم اگر از تابع GetName در تابع GetValidity استفاده نكنم مشكلي پيش نمي ياد و پيغام تا زدن دكمه ok نمايش داده ميشه و بعد از آن هم برنامه ادامه پيدا مي كنه و يدفعه بسته نميشه
حالا به نظر شما مشكل كجاست و چرا يكدفعه برنامه بسته ميشه ؟
ممنون ميشم اگه بازم راهنماييم كنيد

Nima_NF
جمعه 17 آبان 1387, 23:32 عصر
شما تابع GetName را اشتباه نوشته اید و جدا از آن اصلا نیاز نیست این همه کد برای گرفتن نام برنامه کنید!
از توابع استاندارد C و ++C استفاده کنید، پس فقط بنویسید :



char* GetName()
{
char path[1000];
GetModuleFileNameA(NULL,path,1000);

return (strrchr( path, '\\' ) + 1);
}

تابع strrchr رشته شما را از آخرین مرتبه دیدن \ تا انتهای آن برمی گرداند که آن را به علاوه 1 می کنیم تا خود \ در رشته نباشد و آن می شود فقط نام برنامه شما بدون مسیر.

پس نه نیاز به تخصیص حافظه مجدد هست، نه حلقه for و نه ...

برخی از اشکالات کدهای شما :

-در کدهای حلقه دوم for ، مجددا تا 1000 می شمارید در حالی که با new تعداد محدودی حافظه به name اختصاص داده بودید و همراه آن را بدون توجه به انتهایش پر می کردید و این خطای حافظه خواهد داد.

- در حلقه for اولی اشتباها انتهای آرایه 1000 را به عنوان index_end پیدا می کنید، چون رشته شما از نوع TCHAR هست در حالی که به صورت اسکی کارکتر انتهای رشته را مقایسه می کنید، پس اگر پروژه شما اسکی هست تمامی رشته ها را به char تغییر دهید و از توابع اسکی که معمولا به A همراهند استفاده کنید.
اگر هم یونیکد هست در همه جا از TCHAR و از L یا TEXT() استفاده کنید.

- در حلقه ها حتی وقتی به انتهای رشته یا نام می رسید با break از حلقه خارج نمی شوید و تا 1000 پیش می روید!

- بنابر مطالب فوق index های شما اشتباه می شوند، حافظه اشتباه، دسترسی اشتباه و ...

موفق باشید