Поскольку nobugz уже рассмотрел ваш первый вопрос, позвольте мне остановиться на втором. Это не очень сложно понять.
Когда вы компилируете DLL в Windows, компоновщик создает таблицу адресов экспорта (EAT), в которой перечисляются все экспортируемые функции (функции, которые предоставляет DLL) и указатель того, где они реализованы в самой DLL.
При компиляции приложения, которое ссылается на DLL, компоновщик создает таблицу адресов импорта (IAT) со списком всех функций, которые реализованы в других DLL, и именем библиотеки DLL, которая реализует эти функции. Он знает, что функция существует в DLL, из .lib-файла, который вы добавляете в свой проект. Это говорит компоновщику, что функция реализована в DLL.
Затем во время выполнения при загрузке приложения загрузчик Windows проверяет IAT, чтобы узнать, какие DLL нужно загрузить, находит их и обновляет IAT приложения (в памяти), чтобы указывать на экспортируемые функции в загруженной DLL.
Вот основы того, как это работает, надеюсь, я не учел грубых неточностей. И, конечно, P / Invoke - еще один слой поверх этого.
Если вам нужна дополнительная информация о том, как работает DLL, всегда есть документация MSDN , и если вам нужно достаточно подробностей, чтобы заставить вас раскрутиться, прочитайте эти статьи Inside Windows Часть 1 и часть 2