Во-первых, COM похож на черную магию для меня. Но я должен использовать COM dll в одном проекте, я продолжаю работать.
Так, у меня есть DLL, который я разрабатываю, и мне нужны некоторые технические возможности, которые доступны в отдельном COM DLL. Когда я обращаюсь к COM DLL с Depends.exe, я вижу методы как DllGetClassObject () и другие функции, но ни одна из функций я интересуюсь.
У меня есть доступ к COM DLL (наследие) исходный код, но это - путаница, и я хотел бы использовать COM DLL в двоичном файле как большой черный квадрат, не зная то, что продолжается внутри.
Так, как я могу вызвать функции COM DLL от своего использования кода LoadLibrary? Действительно ли это возможно? Если, да, Вы могли бы дать мне пример того, как сделать это?
Я использую Visual Studio 6 для этого проекта.
Большое спасибо!
Как правило, вы бы использовали CoCreateInstance ()
для создания объекта от COM DLL. Когда вы делаете это, нет необходимости загружать DLL сначала и получить адреса proc, как вам нужно будет делать с обычной DLL. Это связано с тем, что Windows «знает» о типах, которые представляет собой COM DLL, в какую DLL их реализуются, и как создавать их создать. (Предполагая, конечно, что COM DLL зарегистрирована, которую она обычно есть).
Предположим, у вас есть COM DLL с интерфейсом IDOG, который вы хотите использовать. В этом случае
interface IDog : IUnknown
{
HRESULT Bark();
};
coclass Dog
{
[default] Interface IDog;
};
IDog* piDog = 0;
CoCreateInstance(CLSID_DOG, 0, CLSCTX_INPROC_SERVER, IID_IDOG, &piDog); // windows will instantiate the IDog object and place the pointer to it in piDog
piDog->Bark(); // do stuff
piDog->Release(); // were done with it now
piDog = 0; // no need to delete it -- COM objects generally delete themselves
Все эти вещи управления памятью могут стать довольно шероховатый, хотя, и ATL предоставляет интеллектуальные указатели, которые делают задачу создания и управления этими объектами немного проще :
CComPtr<IDog> dog;
dog.CoCreateInstance(CLSID_DOG);
dog->Bark();
Когда я сказал выше, что:
Windows «знает» о типах, которые представляет собой COM DLL [... и] Какую DLL они реализуются в
... Я действительно блестел, как именно окна знает это. Это не волшебство, хотя это может показаться немного оккульт-иш.
COM Библиотеки поставляются с библиотеками типа, которые перечислите интерфейсы и кокосоты, которые предоставляют библиотеку. Эта библиотека типа находится в виде файла на вашем жестком диске - очень часто он встроен непосредственно в той же DLL или EXE в качестве библиотеки. Windows знает, где найти библиотеку типа и сама библиотека COM, просматривая в реестре Windows. Записи в реестре Скажите Windows, где на жестком диске находится DLL.
Когда вы звоните CoCreateInstance
, Windows выглядит CLSID в реестре Windows, находит соответствующую DLL, загружает ее и выполняет правильный код в DLL, который реализует объект COM.
Как эта информация попадет в реестр Windows? Когда установлена COM DLL, она зарегистрирована. Это обычно делается бегом REGSVR32.exe , что, в свою очередь, загружает вашу DLL в память и вызывает функцию с именем dllregisterServer
. Эта функция, реализованная на вашем COM-сервере, добавляет информацию о необходимости в реестре. Если вы используете ATL или другой COM Framework, это, вероятно, делается под капотом, чтобы вам не нужно взаимодействовать с реестром напрямую. DLLREGisterServer
требуется только один раз, при установке времени.
Если вы пытаетесь вызвать COCREATEINSTANCE
для COM-объекта, который еще не был зарегистрирован через REGSVR32
/ , процесс DLLGisterver
, затем CoCreateInstance
потерпит неудачу с ошибкой, который говорит:
Класс не зарегистрирован
К счастью, исправление для этого является просто вызовите regsvr32
на вашем COM-сервере, а затем повторите попытку.
Используйте модуль лесозаготовок вместо предупреждений
.
В общем случае вы должны предпочевать CoCreateInstance
или CogetClassObject
, а не доступ к dllgetClassObject
. Но если вы имеете дело с DLL, которую вы не можете, или не хотите, зарегистрироваться, затем ниже описан (часть), что эта функция делает за кулисами.
Учитывая CLSID, DllgetClassObject
позволяет получить объект класса, из которого вы можете создавать экземпляры (через интерфейс ICLASSAffactory
, если я правильно запомню).
Краткое изложение шагов (прошло некоторое время, так как я в последний раз затронул COM, так простите любые очевидные ошибки):
DLLGELASSASCOBJECT (CLSID, IID_ICLASSFFORTORY, & CF)
, где CLSID
- это CLSID, который вы хотите получить объект класса, и CF
, конечно, классовый завод. CF-> CreateInstance (0, IID, & OBJ)
, где IID
- это IID интерфейса, который вы хотели бы использовать, и OBJ
Конечно, объект. ( COCREATEINSTANCE
выполняет шаги 1 и 2. CogetClassObject
Выполняет шаг 1. Используется CogetClassObject
Если вам нужно создать много экземпляров одного класса, Так что шаг 1 не нужно повторять каждый раз.)
Вы не можете напрямую использовать LoadLibrary () с библиотекой COM. CoCreateInstance () вызовет эту функцию, если это еще не сделано, а затем создаст экземпляр класса, который вы реализовали в библиотеке, в кучу и, наконец, вернет вам необработанный указатель на этот объект. Конечно, он может выйти из строя во время процесса, и, следовательно, какой-то механизм для проверки статуса, например HRESULT.
Для простоты использования, вы можете рассматривать COM-библиотеку как обычную DLL с 1) некоторой предопределенной функцией ввода (основной), 2) вам нужно вызвать некоторую предопределенную функцию, такую как CoCreateInstance (), чтобы ввести ее, и принять что это так, потому что так должно быть.
Если библиотека типов встроена в DLL, вы можете импортировать ее в свой проект:
#import "whatever.dll"
Это автоматически сгенерирует файлы заголовков, которые будут включены в ваш проект и позволяют использовать экспортированные объекты.
Если это COM-DLL, все, что вам нужно сделать, это добавить ее в качестве ссылки на свой проект, а затем вы сможете вызывать функции, которые находятся в этой DLL.
Да, вы можете использовать низкоуровневые функции COM, такие как DLLGetClassObject, но зачем вам это?
Сначала добавить
filterContext.HttpContext.Response.Clear();
и это в конце:
filterContext.HttpContext.Response.End();
Надеюсь, это поможет.
-121--2663128-Я бы пошел с boost:: scoped _ ptr здесь:
class A: boost::noncopyable
{
typedef boost::scoped_ptr<B> b_ptr;
b_ptr pb_;
public:
A() : pb_() {}
void calledVeryOften( /*…*/ )
{
pb_.reset( new B( params )); // old instance deallocated
// safely use *pb_ as reference to instance of B
}
};
Нет необходимости в ручном деструкторе, A
не копируется, как это должно быть в вашем оригинальном коде, не утечка памяти при копировании/назначении.
Я бы предложил переосмыслить дизайн, хотя если вам нужно очень часто перераспределять какой-то внутренний государственный объект. Ознакомьтесь с параметрами Flyweight и State узоров.
-121--2666428-Вот небольшой код, показывающий, как получить фабрику классов и использовать ее для создания COM-объекта. Он использует структуру, чтобы сохранить трека дескриптора модуля и указателя функции Dll GetClassObject. Вы должны держаться за дескриптор модуля, пока не закончите работу с COM-объектом.
Чтобы использовать эту функцию, необходимо выделить экземпляр структуры ComModureInfo и установить для szDLL имя файла DLL или полное имя пути. Затем вызовите функцию с идентификатором класса и идентификатором интерфейса COM-объекта, который требуется получить из этой DLL.
typedef struct {
TCHAR szDLL[MAX_PATH];
HMODULE hModule;
HRESULT (WINAPI *pfnGetFactory)(REFCLSID, REFIID, void**);
} ComModuleInfo;
HRESULT CreateCOMObject(
ComModuleInfo & mod, // [in,out]
REFCLSID iidClass, // [in] CLSID of the COM object to create
REFIID iidInterface, // [in] GUID of the interface to get
LPVOID FAR* ppIface) // [in] on success, interface to the COM object is returned
{
HRESULT hr = S_OK;
*ppIface = NULL; // in case we fail, make sure we return a null interface.
// init the ComModuleInfo if this is the first time we have seen it.
//
if ( ! mod.pfnGetFactory)
{
if ( ! mod.hModule)
{
mod.hModule = LoadLibrary(mod.szDLL);
if ( ! mod.hModule)
return HRESULT_FROM_WIN32(GetLastError());
}
mod.pfnGetFactory = (HRESULT (WINAPI *)(REFCLSID, REFIID, void**))GetProcAddress(mod.hModule, "DllGetClassObject");
if ( ! mod.pfnGetFactory)
return HRESULT_FROM_WIN32(GetLastError());
}
IClassFactory* pFactory = NULL;
hr = mod.pfnGetFactory(iidClass, IID_IClassFactory, (void**)&pFactory);
if (SUCCEEDED(hr))
{
hr = pFactory->CreateInstance(NULL, iidInterface, (void**)ppIface);
pFactory->Release();
}
return hr;
}