เหตุใดฉันจึงใช้ __declspec(dllexport) เพื่อส่งออก DllGetClassObject() จาก COM DLL ไม่ได้

ฉันกำลังพัฒนา COM dll และพยายามส่งออกเมธอด DllGetClassObject() ด้วย __declspec(dllexport)

นี่คือคำประกาศของฉัน:

extern "C" HRESULT __declspec(dllexport) __stdcall DllGetClassObject(REFCLSID rclsid, 
                                                             REFIID riid, void** ppv)

แต่ฉันยังคงได้รับข้อผิดพลาดนี้:

error C2375: 'DllGetClassObject' : redefinition; different linkage

ดังนั้นฉันจึงพยายามตรวจสอบการเกิดขึ้นของคำจำกัดความ DllGetClassObject ทั้งหมด จึงพบสิ่งต่อไปนี้ใน ObjBase.h

STDAPI  DllGetClassObject(__in REFCLSID rclsid, __in REFIID riid, __deref_out LPVOID FAR* ppv);

STDAPI กลายเป็นเช่นนี้:

#define STDAPI                  EXTERN_C HRESULT STDAPICALLTYPE

กล่าวอีกนัยหนึ่ง มันเป็นเช่นนี้:

#define STDAPI                  extern "C" HRESULT __stdcall

ตาม MSDN:

ในการส่งออกฟังก์ชัน คีย์เวิร์ด __declspec(dllexport) จะต้องปรากฏทางด้านซ้ายของคีย์เวิร์ด Calling-Convention หากมีการระบุคีย์เวิร์ด

แต่คำประกาศของฉันที่กล่าวถึงก่อนหน้านี้ไม่ได้ผล

COM DLL ต้อง ส่งออกวิธีการของพวกเขาด้วยไฟล์ def หรือไม่


อัปเดต 1

ฉันทดสอบการประกาศของฉันด้วยชื่อวิธีการอื่น ดังที่แสดงด้านล่าง:

extern "C" HRESULT __declspec(dllexport) __stdcall f()
{
    return S_OK;
}

และวิธีนี้ก็ส่งออกได้สำเร็จ ดังนั้นตัวระบุเหล่านี้จึงสามารถใช้ร่วมกันได้ ดูเหมือนว่าคอมไพเลอร์ Visual C++ จะใช้ STDAPI และ extern "C" HRESULT __declspec(dllexport) __stdcall ว่าเข้ากันไม่ได้


person smwikipedia    schedule 11.08.2010    source แหล่งที่มา
comment
ลองใช้มาโครดูหรือยังครับ? เช่น. __declspec(dllexport) STDAPI DllGetClassObject(...);   -  person JSBձոգչ    schedule 11.08.2010
comment
ขอบคุณสำหรับการตอบกลับของคุณ. ฉันลองแล้ว ไม่มีข้อผิดพลาดในการรวบรวมในขณะนี้ แต่ไม่มีการส่งออกเช่นกัน ฉันตรวจสอบอีกครั้งกับ DLL Exports Viewer และ dumpbin.exe มันช่างเป็นภาวะที่กลืนไม่เข้าคายไม่ออก นี่เป็นหนึ่งในข้อบกพร่องที่น่ารังเกียจของ Microsoft หรือไม่   -  person smwikipedia    schedule 11.08.2010


คำตอบ (3)


ปัญหานี้เกิดขึ้น ฉันคิดว่าเพราะโดยปกติแล้วฟังก์ชัน __stdcall (สำหรับรุ่น 32 บิต) จะได้รับการตกแต่งด้วยคำนำหน้าขีดล่างและ @count postfix แต่ถ้าฟังก์ชั่นถูกทำเครื่องหมายเป็น __declspec(dllexport) มีการเพิ่มการตกแต่งเพิ่มเติมด้วย (__imp ฉันคิดว่า)

คุณอาจหลีกเลี่ยงการใช้ไฟล์ .def กับ pragma ต่อไปนี้ได้ หากคุณยินดีที่จะอยู่กับ pragma (ฉันคิดว่าฉันจะเลือกใช้ไฟล์ .def):

#pragma comment( linker, "/export:DllGetClassObject=_DllGetClassObject@12" )

โปรดทราบว่าสำหรับรุ่น x64 คุณอาจต้องคอมไพล์ pragma แบบมีเงื่อนไข ซึ่งฉันคิดว่าจะเป็น:

#pragma comment( linker, "/export:DllGetClassObject" )
person Michael Burr    schedule 11.08.2010
comment
แค่นั้นแหละ~ ขอบคุณไมเคิล :) - person smwikipedia; 15.08.2010
comment
@Michael การทำเช่นนี้ DLL จะมีการส่งออก 2 รายการสำหรับแต่ละฟังก์ชัน DllGetClassObject และ _DllGetClassObject@12 (อย่างน้อยคือสิ่งที่ฉันเห็นได้ด้วย Dependency Walker) มีวิธีส่งออกเฉพาะ DllGetClassObject หรือไม่ - person jyz; 24.07.2013
comment
โปรดทราบว่า COM คาดว่าจะมีการส่งออกชื่อที่ยังไม่แยกส่วนออกตั้งแต่แรก (ดังนั้นจึงไม่จำเป็นต้องมีการแยกชื่อในไฟล์ .def) - person Cameron; 23.04.2014

ไม่มีการคอมไพล์เนื่องจากการประกาศดั้งเดิมใน objbase.h ไม่มีแอตทริบิวต์ __declspec(dllexport) คุณไม่สามารถเพิ่มลงในคำจำกัดความได้ ช่วยไม่ได้หรอกค่ะ การประดับชื่อไม่เหมาะสม ไมเคิลแสดงให้คุณเห็นว่าต้องทำอย่างไรกับเรื่องนั้น

person Hans Passant    schedule 11.08.2010
comment
ขอบคุณฮันส์ ฉันซาบซึ้งมากสำหรับคำตอบของคุณสำหรับคำถามของฉัน ไม่ใช่แค่อันนี้ :) - person smwikipedia; 15.08.2010

ฉันจะออกไปบนแขนขาแล้วพูดว่าใช่

แม้แต่ Visual Studio 2008 ก็ยังสร้างไฟล์ .def สำหรับโครงการ ATL COM .dll โดยอัตโนมัติ

person MSN    schedule 11.08.2010