Titik masuk DllMain

Titik entri opsional ke pustaka tautan dinamis (DLL). Ketika sistem memulai atau mengakhiri proses atau utas, sistem memanggil fungsi titik entri untuk setiap DLL yang dimuat menggunakan utas pertama proses. Sistem ini juga memanggil fungsi titik entri untuk DLL ketika dimuat atau dibongkar menggunakan fungsi LoadLibrary dan FreeLibrary .

Contoh

BOOL WINAPI DllMain(
    HINSTANCE hinstDLL,  // handle to DLL module
    DWORD fdwReason,     // reason for calling function
    LPVOID lpvReserved )  // reserved
{
    // Perform actions based on the reason for calling.
    switch( fdwReason ) 
    { 
        case DLL_PROCESS_ATTACH:
         // Initialize once for each new process.
         // Return FALSE to fail DLL load.
            break;

        case DLL_THREAD_ATTACH:
         // Do thread-specific initialization.
            break;

        case DLL_THREAD_DETACH:
         // Do thread-specific cleanup.
            break;

        case DLL_PROCESS_DETACH:
        
            if (lpvReserved != nullptr)
            {
                break; // do not do cleanup if process termination scenario
            }
            
         // Perform any necessary cleanup.
            break;
    }
    return TRUE;  // Successful DLL_PROCESS_ATTACH.
}

Ini adalah contoh dari Fungsi Entry-Point Pustaka Dynamic-Link.

Peringatan

Ada batasan signifikan pada apa yang dapat Anda lakukan dengan aman di titik masuk DLL. Lihat Praktik Terbaik Umum untuk API Windows tertentu yang tidak aman untuk dipanggil di DllMain. Jika Anda memerlukan apa pun kecuali inisialisasi yang paling sederhana, lakukan itu dalam fungsi inisialisasi untuk DLL. Anda dapat mengharuskan aplikasi untuk memanggil fungsi inisialisasi setelah DllMain berjalan dan sebelum mereka memanggil fungsi lain di DLL.

Sintaks

BOOL WINAPI DllMain(
  _In_ HINSTANCE hinstDLL,
  _In_ DWORD     fdwReason,
  _In_ LPVOID    lpvReserved
);

Parameter

hinstDLL [in]

Handel ke modul DLL. Nilai adalah alamat dasar DLL. HINSTANCE DLL sama dengan HMODULE DLL, sehingga hinstDLL dapat digunakan dalam panggilan ke fungsi yang memerlukan handel modul.

fdwReason [in]

Kode alasan yang menunjukkan mengapa fungsi titik entri DLL dipanggil. Parameter ini bisa menjadi salah satu nilai berikut.

Nilai Makna
DLL_PROCESS_ATTACH
1
DLL sedang dimuat ke ruang alamat virtual dari proses saat ini sebagai akibat dari proses memulai atau sebagai akibat dari panggilan ke LoadLibrary. DLL dapat menggunakan kesempatan ini untuk menginisialisasi data instans apa pun atau menggunakan fungsi TlsAlloc untuk mengalokasikan indeks penyimpanan lokal utas (TLS).
Parameter lpvReserved menunjukkan apakah DLL sedang dimuat secara statis atau dinamis.
DLL_PROCESS_DETACH
0
DLL sedang dibongkar dari ruang alamat virtual proses panggilan karena dimuat tidak berhasil atau jumlah referensi telah mencapai nol (proses telah dihentikan atau disebut FreeLibrary satu kali untuk setiap kali disebut LoadLibrary).
Parameter lpvReserved menunjukkan apakah DLL sedang dibongkar sebagai akibat dari panggilan FreeLibrary , kegagalan untuk memuat, atau memproses penghentian.
DLL dapat menggunakan kesempatan ini untuk memanggil fungsi TlsFree untuk membebaskan indeks TLS yang dialokasikan dengan menggunakan TlsAlloc dan untuk membebaskan data lokal utas apa pun.
Perhatikan bahwa utas yang menerima pemberitahuan DLL_PROCESS_DETACH belum tentu sama dengan utas yang menerima pemberitahuan DLL_PROCESS_ATTACH .
DLL_THREAD_ATTACH
2
Proses saat ini adalah membuat utas baru. Ketika ini terjadi, sistem memanggil fungsi titik masuk dari semua DLL yang saat ini melekat pada proses. Panggilan dilakukan dalam konteks utas baru. DLL dapat menggunakan kesempatan ini untuk menginisialisasi slot TLS untuk utas. Utas yang memanggil fungsi titik entri DLL dengan DLL_PROCESS_ATTACH tidak memanggil fungsi titik entri DLL dengan DLL_THREAD_ATTACH.
Perhatikan bahwa fungsi titik entri DLL dipanggil dengan nilai ini hanya oleh utas yang dibuat setelah DLL dimuat oleh proses. Ketika DLL dimuat menggunakan LoadLibrary, utas yang ada tidak memanggil fungsi titik entri dari DLL yang baru dimuat.
DLL_THREAD_DETACH
3
Utas keluar dengan bersih. Jika DLL telah menyimpan pointer untuk mengalokasikan memori di slot TLS, dll harus menggunakan kesempatan ini untuk membebaskan memori. Sistem memanggil fungsi titik entri dari semua DLL yang saat ini dimuat dengan nilai ini. Panggilan dilakukan dalam konteks utas keluar.

lpvReserved [in]

Jika fdwReasonDLL_PROCESS_ATTACH, lpvReserved adalah NULL untuk beban dinamis dan non-NULL untuk beban statis.

Jika fdwReasonDLL_PROCESS_DETACH, lpvReserved adalah NULL jika FreeLibrary telah dipanggil atau beban DLL gagal dan non-NULL jika prosesnya berakhir.

Nilai kembali

Ketika sistem memanggil fungsi DllMain dengan nilai DLL_PROCESS_ATTACH , fungsi mengembalikan TRUE jika berhasil atau FALSE jika inisialisasi gagal. Jika nilai yang dikembalikan adalah FALSE saat DllMain dipanggil karena proses menggunakan fungsi LoadLibrary , LoadLibrary mengembalikan NULL. (Sistem segera memanggil fungsi titik entri Anda dengan DLL_PROCESS_DETACH dan membongkar DLL.) Jika nilai yang dikembalikan adalah FALSE saat DllMain dipanggil selama inisialisasi proses, proses berakhir dengan kesalahan. Untuk mendapatkan informasi kesalahan yang diperluas, hubungi GetLastError.

Ketika sistem memanggil fungsi DllMain dengan nilai apa pun selain DLL_PROCESS_ATTACH, nilai yang dikembalikan diabaikan.

Keterangan

DllMain adalah tempat penampung untuk nama fungsi yang ditentukan pustaka. Anda harus menentukan nama aktual yang Anda gunakan saat membuat DLL. Untuk informasi selengkapnya, lihat dokumentasi yang disertakan dengan alat pengembangan Anda.

Selama startup proses awal atau setelah panggilan ke LoadLibrary, sistem memindai daftar DLL yang dimuat untuk proses tersebut. Untuk setiap DLL yang belum dipanggil dengan nilai DLL_PROCESS_ATTACH , sistem memanggil fungsi titik masuk DLL. Panggilan ini dilakukan dalam konteks utas yang menyebabkan ruang alamat proses berubah, seperti utas utama proses atau utas yang disebut LoadLibrary. Akses ke titik masuk diserialisasikan oleh sistem secara proses. Utas di DllMain menahan kunci loader sehingga tidak ada DLL tambahan yang dapat dimuat atau diinisialisasi secara dinamis.

Jika fungsi titik entri DLL mengembalikan FALSE setelah pemberitahuan DLL_PROCESS_ATTACH , fungsi menerima pemberitahuan DLL_PROCESS_DETACH dan DLL segera dibongkar. Namun, jika kode DLL_PROCESS_ATTACH melempar pengecualian, fungsi titik entri tidak akan menerima pemberitahuan DLL_PROCESS_DETACH .

Ada kasus di mana fungsi titik entri dipanggil untuk utas yang mengakhiri bahkan jika fungsi titik masuk tidak pernah dipanggil dengan DLL_THREAD_ATTACH untuk utas:

  • Utas adalah utas awal dalam proses, sehingga sistem memanggil fungsi titik masuk dengan nilai DLL_PROCESS_ATTACH .
  • Utas sudah berjalan ketika panggilan ke fungsi LoadLibrary dilakukan, sehingga sistem tidak pernah memanggil fungsi titik masuk untuk itu.

Ketika DLL dibongkar dari proses sebagai akibat dari beban DLL yang gagal, penghentian proses, atau panggilan ke FreeLibrary, sistem tidak memanggil fungsi titik masuk DLL dengan nilai DLL_THREAD_DETACH untuk utas individu dari proses. DLL hanya dikirimi pemberitahuan DLL_PROCESS_DETACH . DLL dapat mengambil kesempatan ini untuk membersihkan semua sumber daya untuk semua utas yang diketahui dll.

Saat menangani DLL_PROCESS_DETACH, DLL harus membebaskan sumber daya seperti memori tumpukan hanya jika DLL dibongkar secara dinamis (parameter lpvReserved adalah NULL). Jika proses diakhiri (parameter lpvReserved bukan NULL), semua utas dalam proses kecuali utas saat ini telah keluar sudah atau telah dihentikan secara eksplisit oleh panggilan ke fungsi ExitProcess , yang mungkin meninggalkan beberapa sumber daya proses seperti tumpukan dalam keadaan tidak konsisten. Dalam hal ini, tidak aman bagi DLL untuk membersihkan sumber daya. Sebaliknya, DLL harus memungkinkan sistem operasi untuk mengklaim kembali memori.

Jika Anda mengakhiri proses dengan memanggil TerminateProcess atau TerminateJobObject, DLL proses tersebut tidak menerima pemberitahuan DLL_PROCESS_DETACH . Jika Anda mengakhiri utas dengan memanggil TerminateThread, DLL utas tersebut tidak menerima pemberitahuan DLL_THREAD_DETACH .

Fungsi titik entri harus hanya melakukan tugas inisialisasi atau penghentian sederhana. Ini tidak boleh memanggil fungsi LoadLibrary atau LoadLibraryEx (atau fungsi yang memanggil fungsi-fungsi ini), karena ini dapat membuat perulangan dependensi dalam urutan beban DLL. Ini dapat mengakibatkan DLL digunakan sebelum sistem menjalankan kode inisialisasinya. Demikian pula, fungsi titik entri tidak boleh memanggil fungsi FreeLibrary (atau fungsi yang memanggil FreeLibrary) selama penghentian proses, karena ini dapat mengakibatkan DLL digunakan setelah sistem menjalankan kode penghentiannya.

Karena Kernel32.dll dijamin akan dimuat di ruang alamat proses ketika fungsi titik entri dipanggil, fungsi panggilan di Kernel32.dll tidak mengakibatkan DLL digunakan sebelum kode inisialisasinya dijalankan. Oleh karena itu, fungsi titik entri dapat memanggil fungsi dalam Kernel32.dll yang tidak memuat DLL lain. Misalnya, DllMain dapat membuat objek sinkronisasi seperti bagian dan mutex penting, dan menggunakan TLS. Sayangnya, tidak ada daftar fungsi aman yang komprehensif dalam Kernel32.dll.

Fungsi panggilan yang memerlukan DLL selain Kernel32.dll dapat mengakibatkan masalah yang sulit didiagnosis. Misalnya, memanggil fungsi Pengguna, Shell, dan COM dapat menyebabkan kesalahan pelanggaran akses, karena beberapa fungsi memuat komponen sistem lainnya. Sebaliknya, fungsi panggilan seperti ini selama penghentian dapat menyebabkan kesalahan pelanggaran akses karena komponen yang sesuai mungkin sudah dibongkar atau tidak diinisialisasi.

Karena pemberitahuan DLL diserialisasikan, fungsi titik entri tidak boleh mencoba berkomunikasi dengan utas atau proses lain. Kebuntuan dapat terjadi sebagai akibatnya.

Untuk informasi tentang praktik terbaik saat menulis DLL, lihat Praktik terbaik pustaka tautan dinamis.

Jika DLL Anda ditautkan dengan pustaka run-time C (CRT), titik masuk yang disediakan oleh CRT memanggil konstruktor dan destruktor untuk objek C++ global dan statis. Oleh karena itu, pembatasan untuk DllMain ini juga berlaku untuk konstruktor dan destruktor dan kode apa pun yang dipanggil dari mereka.

Pertimbangkan untuk memanggil DisableThreadLibraryCalls saat menerima DLL_PROCESS_ATTACH, kecuali DLL Anda ditautkan dengan pustaka run-time C statis (CRT).

Persyaratan

Persyaratan Nilai
Klien minimum yang didukung
Windows XP [hanya aplikasi desktop]
Server minimum yang didukung
Windows Server 2003 [hanya aplikasi desktop]
Header
Process.h

Lihat juga

Fungsi Entry-Point Pustaka Dynamic-Link

Fungsi Pustaka Dynamic-Link

FreeLibrary

GetModuleFileName

LoadLibrary

TlsAlloc

TlsFree

DisableThreadLibraryCalls