ตรงกันข้ามกับคำแนะนำโดยคำตอบอื่น ๆ การใช้DllImport
คุณลักษณะยังคงเป็นวิธีที่ถูกต้อง
ฉันไม่เข้าใจว่าทำไมคุณไม่สามารถทำเหมือนคนอื่นในโลกและระบุเส้นทางที่สัมพันธ์กับ DLL ของคุณ ใช่เส้นทางที่ติดตั้งแอปพลิเคชันของคุณจะแตกต่างกันไปในคอมพิวเตอร์ของคนอื่น แต่โดยทั่วไปก็เป็นกฎสากลเมื่อนำมาปรับใช้ DllImport
กลไกการออกแบบที่มีในใจ
ในความเป็นจริงมันไม่ได้แม้แต่จะDllImport
จัดการกับมัน มันเป็นกฎการโหลด Win32 DLL แบบดั้งเดิมที่ควบคุมสิ่งต่างๆโดยไม่คำนึงว่าคุณกำลังใช้ wrappers ที่มีการจัดการที่มีประโยชน์หรือไม่ (P / Invoke marshaller เพิ่งเรียกLoadLibrary
) กฎเหล่านั้นมีรายละเอียดมากมายที่นี่แต่สิ่งสำคัญถูกคัดลอกมาที่นี่:
ก่อนที่ระบบจะค้นหา DLL จะตรวจสอบสิ่งต่อไปนี้:
- ถ้า DLL ที่มีชื่อโมดูลเดียวกันถูกโหลดในหน่วยความจำแล้วระบบจะใช้ DLL ที่โหลดแล้วไม่ว่าจะเป็นไดเรกทอรีใดระบบจะไม่ค้นหา DLL
- หาก DLL อยู่ในรายการ DLLs ที่รู้จักสำหรับรุ่นของ Windows ที่แอปพลิเคชันทำงานอยู่ระบบจะใช้สำเนา DLL ที่รู้จัก (และ DLL ที่ขึ้นกับ DLL ที่รู้จักถ้ามี) ระบบไม่ค้นหา DLL
หากSafeDllSearchMode
เปิดใช้งาน (ค่าเริ่มต้น) ลำดับการค้นหาจะเป็นดังนี้:
- ไดเรกทอรีที่โหลดแอปพลิเคชัน
- ไดเรกทอรีระบบ ใช้
GetSystemDirectory
ฟังก์ชั่นเพื่อรับเส้นทางของไดเรกทอรีนี้
- ไดเรกทอรีระบบ 16 บิต ไม่มีฟังก์ชั่นที่ได้รับเส้นทางของไดเรกทอรีนี้ แต่มันถูกค้นหา
- ไดเรกทอรี Windows ใช้
GetWindowsDirectory
ฟังก์ชั่นเพื่อรับเส้นทางของไดเรกทอรีนี้
- ไดเรกทอรีปัจจุบัน
- ไดเรกทอรีที่ระบุไว้ใน
PATH
ตัวแปรสภาพแวดล้อม โปรดทราบว่านี่ไม่รวมเส้นทางต่อแอปพลิเคชันที่ระบุโดยคีย์รีจิสทรีของ App Paths ไม่มีการใช้คีย์ App Paths เมื่อคำนวณเส้นทางการค้นหา DLL
ดังนั้นหากคุณตั้งชื่อ DLL ของคุณเหมือนกับระบบ DLL (ซึ่งคุณไม่ควรทำอย่างชัดเจนไม่ว่าในกรณีใด ๆ ) ลำดับการค้นหาเริ่มต้นจะเริ่มค้นหาในไดเรกทอรีที่โหลดแอปพลิเคชันของคุณ หากคุณวาง DLL ไว้ในระหว่างการติดตั้งจะพบได้ ปัญหาที่ซับซ้อนทั้งหมดหายไปหากคุณใช้เส้นทางที่สัมพันธ์กัน
แค่เขียน:
[DllImport("MyAppDll.dll")] // relative path; just give the DLL's name
static extern bool MyGreatFunction(int myFirstParam, int mySecondParam);
แต่ถ้าวิธีนี้ใช้ไม่ได้ไม่ว่าด้วยเหตุผลใดและคุณต้องบังคับให้แอปพลิเคชันค้นหาไดเรกทอรีอื่นสำหรับ DLL คุณสามารถปรับเปลี่ยนเส้นทางการค้นหาเริ่มต้นโดยใช้SetDllDirectory
ฟังก์ชันได้
โปรดทราบว่าตามเอกสาร:
หลังจากเรียกSetDllDirectory
เส้นทางการค้นหา DLL มาตรฐานคือ:
- ไดเรกทอรีที่โหลดแอปพลิเคชัน
- ไดเรกทอรีที่ระบุโดย
lpPathName
พารามิเตอร์
- ไดเรกทอรีระบบ ใช้
GetSystemDirectory
ฟังก์ชั่นเพื่อรับเส้นทางของไดเรกทอรีนี้
- ไดเรกทอรีระบบ 16 บิต ไม่มีฟังก์ชั่นที่ได้รับเส้นทางของไดเรกทอรีนี้ แต่มันถูกค้นหา
- ไดเรกทอรี Windows ใช้
GetWindowsDirectory
ฟังก์ชั่นเพื่อรับเส้นทางของไดเรกทอรีนี้
- ไดเรกทอรีที่ระบุไว้ใน
PATH
ตัวแปรสภาพแวดล้อม
ดังนั้นตราบใดที่คุณเรียกใช้ฟังก์ชันนี้ก่อนที่คุณจะเรียกใช้ฟังก์ชันที่นำเข้าจาก DLL เป็นครั้งแรกคุณสามารถปรับเปลี่ยนเส้นทางการค้นหาเริ่มต้นที่ใช้เพื่อค้นหา DLLs ประโยชน์ที่ได้รับแน่นอนคือคุณสามารถส่งผ่านค่าไดนามิกไปยังฟังก์ชันนี้ซึ่งคำนวณได้ในขณะใช้งาน ไม่สามารถใช้DllImport
แอตทริบิวต์ได้ดังนั้นคุณจะยังคงใช้พา ธ สัมพัทธ์ (ชื่อของ DLL เท่านั้น) ที่นั่นและพึ่งพาลำดับการค้นหาใหม่เพื่อค้นหาให้คุณ
คุณจะต้อง P / เรียกใช้ฟังก์ชันนี้ การประกาศมีลักษณะดังนี้:
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool SetDllDirectory(string lpPathName);