Войти

Показать полную графическую версию : [решено] *DirectX* | DShow и С++, проблема с линковкой программ


Admiral
01-02-2006, 01:55
Кто работать с библиотеками ДиректХ (в особености DirectShow) из под С/С++?
Под Делфи 6/7 всё гладко проходит.
Начал писать под С++ (среда Visual Studio 6.0), однако сразу напоролса на сложности. Проект компилируется, а при попитке получить ЕХЕ линковщик сбоит error LNK2001 unresolved external symbol.
Хотя текст файл официально опубликован на Микрософт (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directshow/htm/howtoplayafile.asp)

Спасибо за внимание.

P/S Вот сам код где пробуем играть видео файл посредство DShow в среде С++

#include <dshow.h>
void main(void)
{
IGraphBuilder *pGraph = NULL;
IMediaControl *pControl = NULL;
IMediaEvent *pEvent = NULL;

// Initialize the COM library.
HRESULT hr = CoInitialize(NULL);
if (FAILED(hr))
{
printf("ERROR - Could not initialize COM library");
return;
}

// Create the filter graph manager and query for interfaces.
hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
IID_IGraphBuilder, (void **)&pGraph);
if (FAILED(hr))
{
printf("ERROR - Could not create the Filter Graph Manager.");
return;
}

hr = pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl);
hr = pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent);

// Build the graph. IMPORTANT: Change this string to a file on your system.
hr = pGraph->RenderFile(L"C:\\Example.avi", NULL);
if (SUCCEEDED(hr))
{
// Run the graph.
hr = pControl->Run();
if (SUCCEEDED(hr))
{
// Wait for completion.
long evCode;
pEvent->WaitForCompletion(INFINITE, &evCode);

// Note: Do not use INFINITE in a real application, because it
// can block indefinitely.
}
}
pControl->Release();
pEvent->Release();
pGraph->Release();
CoUninitialize();
}

ivank
01-02-2006, 16:08
Admiral
Эта ошибка означает, что компилятор не находит реализацию (т.е. непосредственно точку входа в объектном коде) какой-то из использованных функций. Все WinAPI функции, конечно реализованны в соответствующих системных .dll, но компилятор то об этом не знает и даже не умеет напрямую из dll функции импортировать (вернее, раньше не умел, а сейчас с помощью специальных прагм это возможно, вроде. Но нестандартно совсем). Поэтому создаются специальные .lib-заглушки для системных вызовов. Наиболее часто используемые обычно добавляются IDE в проект при его создании автоматически. Я бы поставил на то, что у вас не подключена к проекту ole32.lib, в которой находятся заглушки для CoCreateInstance и иже с ним. Но точно можно будет сказать, если вы приведёте весь текст ошибки, где указывается в том числе и не найденное имя, а по имени уже можно найти и библиотеку соответствующую.

Admiral
01-02-2006, 22:39
ivank
Спасибо за ответ. Теперь стало понятно где искать проблему.

...а сейчас с помощью специальных прагм это возможно, вроде. Но нестандартно совсем
Что это за программы? И действительно ли они столь существенны?
у вас не подключена к проекту ole32.lib
Она подключена по умолчанию. А вот strmiids.lib как раз не мешало (на него я вышел, посмотрев файл с расширением dsp от BGmusic (http://msdn.microsoft.com/library/default.asp?url=/archive/en-us/directx9_c_Summer_03/directX/htm/bgmusicsample.asp) ). После чего всё заработало!

А на счёт у вас не подключена к проекту .lib ... но точно можно будет сказать, если вы приведёте весь текст ошибки, где указывается в том числе и не найденное имя, а по имени уже можно найти и библиотеку соответствующую.
то как по
main.obj : error LNK2001: unresolved external symbol _IID_IVideoWindow
main.obj : error LNK2001: unresolved external symbol _IID_IMediaControl
main.obj : error LNK2001: unresolved external symbol _CLSID_FilterGraph
main.obj : error LNK2001: unresolved external symbol _IID_IGraphBuilder
можно определить что нехватает?
Я полагаю что опытный сишних ориентируэтса где в какой бибилиотеке что прописано... А начальный? Мануалы читать?

А какой оператор можно использовать в коде для подключения библиотек (что б было видно непосредственно, а не так через Project->Settings (ALT+F7))?
И почему при добавлении /stack:0x200000,0x200000 /subsystem:windows /machine:I386 /ignore:4089 /ignore:4078 в Project Options выдайотса аналогичная ошибка
LIBCD.lib(wincrt0.obj) : error LNK2001: unresolved external symbol _WinMain@16 ?

Р.S
Спасибо за вступительную теорию.
А то я сомневался, что MSVS 6.0 весь битый и ничего путёвого в нём реально не напишиш (напишеш но не получиш ЕХЕ). В Делфи как то проше, но для системных прог С++, как мне кажетса, лутше предназначен.

ivank
02-02-2006, 13:08
Во-первых, моё предположение всё таки оказалось ложным. Т.к. не найдена была не функция, а экспортируемые переменные. Поскольку гуиды по сути своей шестнадцатибайтные стркутуры, то им надо где-то храниться. Хранят и задают значение _одному_ экземпляру структуры, которй описан/хранится в соответствующем объектном модуле (библиотеке в данном случае), в остальных местах на него тольок _ссылаются_. Поэтому если не слинковать программу с соответствующим файлом, то эти ссылки останутся ни к чему не привязанными, что и произошло. Опять же с помощью расшерений MSVC можно приписать IID/GUID прямо к интерфейсу в месте его описания. Что не есть стандартно.

...а сейчас с помощью специальных прагм это возможно, вроде. Но нестандартно совсемЧто это за программы? И действительно ли они столь существенны?Не программы, а прагмы. #pragma <и ещё что-то> Это директивы компилятору, с помощью них можно многое сделать, но понимать это будет лишь MSVC, остальные компиляторы имеют свои прагмы. Полные перечень прагм можно найти в MSDN'е.

то как поmain.obj : error LNK2001: unresolved external symbol _IID_IVideoWindow
main.obj : error LNK2001: unresolved external symbol _IID_IMediaControl
main.obj : error LNK2001: unresolved external symbol _CLSID_FilterGraph
main.obj : error LNK2001: unresolved external symbol _IID_IGraphBuilder
можно определить что нехватает?
Там перечислены имена, которые не удалось найти. Находите их в документации и опеределяете к какой библиотеке они отнсятся, там же будет написано, какие требуется подключить у проекту .lib, что б всё заработало.

А какой оператор можно использовать в коде для подключения библиотек (что б было видно непосредственно, а не так через Project->Settings (ALT+F7))?Какая-то #pragma, не помнб поскольку MSVC уже давно не пользуюсь.

И почему при добавлении /stack:0x200000,0x200000 /subsystem:windows /machine:I386 /ignore:4089 /ignore:4078 в Project Options выдайотса аналогичная ошибкаЕсли я правильно помню, то проблема в /subsystem:windows.

В принципе можно выделить два типа приложение - консольные и windows. Первые это /subsystem:console. При этом линкер создаёт точку входа в программу, в которой инициализируются стандартные библиотеки, включая ввод-вывод на консоль (наверное, консоль тоже создаётся заодно) и затем вызывается функция main. Второй тип приложений - windows приложения. /subsystem:windows. При этом линкером создаётся точка входа в программу, в которой то же что-то инициализируется и затем вызывается функция WinMain, консоль при этом не создаётся.

Соответственно, у вас д.б. функция WinMain с четырьмя параметрами, а не main. Всё.

pva
02-02-2006, 14:29
Когда мне нехватает unresolved external XXXX, я ищу файлы *.lib, содержащие текст XXXX и указываю их линкеру. У меня Metrowerks CodeWarrior 8.0. Там достаточно *.lib к проекту добавить.

Admiral
01-07-2006, 16:45
А как передать программе имя файла который надо проиграть?

Взять к примеру параметры функции main(int argc, char* argv[]).
В коде hr = pGraph->RenderFile(L"C:\\Example.avi", NULL) второй параметр должен быть типа const unsigned short * , а в фунции main второй (и т.д) параметр типа char* .
Если заменить main(int argc, char* argv[]) на main(int argc, const unsigned short * argv[]) (что естественно нарушает порядок функции main()) программа запустится (только с параметром, без параметров выдаст ошибку), но проигрывать нечего не будет (что и не удивительно ведь main() нарушен).
Значит, работать надо со строчкой чтения файла (в самой программе - L"C:\\Example.avi"где L– это приведение типа как я понял).
Если кто знает как можно ещё реализировать , то поделитесь кодом плиз.
Спасибо за внимание.

pva
01-07-2006, 18:53
На сколько я понял, второй параметр (это должно быть написано в *.h) описан как BSTR* или WSTR*, что по сути - одно и тоже, short*. Скорее вего имеется ввиду уникодовская строка.

//#include <string>

// поясняющая вырезка из моей библиотеки
std::wstring widen(const std::string& s)
{
std::wstring w(s.size(), wchar_t());
MultiByteToWideChar(CP_ACP, 0, &s[0], w.size(), &w[0], w.size());
return w;
}

...

void foo(char* arg)
{
std::wstring wstr = widen(std::string(arg));
...

hr = pGraph->RenderFile(L"C:\\Example.avi", wstr.c_str());
}

Admiral
05-05-2008, 20:31
К 1000му просмотру темы, публикую решение. Впрочем, именно сабжевое было найдено ещё тогда – программа линковалась. Просто аппетит возрос и захотелось немного усложнить программу сабжа.

Решение: использовать в коде директивы компилятору #pragma, а в данном конкретном случаи #pragma comment( lib, "strmiids" ) как подсказал ivank. Так же можно подключить через меню, как описано в посте №3
Как найти нужную? Либо искать аналогичные проекты, просматривать документацию или искать по содержимому как рекомендует pva
И самое главное, нужно чётко знать какой сейчас проект: консольный, где main рулит, или оконный, где WinMain уже. Тогда не будет проблемы линкования как в посте №3. Регистр имеет значение: пишем main с меленькой буквы.

pva я воспользовался функцией MultiByteToWideChar и всё заработало как я того хотел. Выходит параметры приложения воспринимаются кодом как набор байтов, которые она и конвертит в символы.
Как её используют нашёл в этом проекте -> http://csclab.murraystate.edu/bob.pilgrim/info/game_stuff/DirectX%20(C++)/Samples/C++/DirectShow/Misc/ASFCopy/asfcopy.cpp.
Вот её описание в MSDN -> http://msdn.microsoft.com/en-us/library/ms776413.aspx
Полные перечень прагм можно найти в MSDN'е. »
Он лайн версия -> http://msdn.microsoft.com/en-us/library/aa273917(VS.60).aspx
Вот собственно код, который линкуется и работает как я хотел.

#pragma comment( lib, "strmiids" )
#include <dshow.h>

void WaitForCompletion(IGraphBuilder *pGraph)
{
HRESULT hr;
LONG lEvCode = 0;
IMediaEvent *pEvent;

if (!pGraph)
return;

hr = pGraph->QueryInterface(IID_IMediaEvent, (void **) &pEvent);
if (SUCCEEDED(hr))
{
do
{
MSG Message;

while(PeekMessage(&Message, NULL, 0, 0, TRUE))
{
TranslateMessage(&Message);
DispatchMessage(&Message);
}

hr = pEvent->WaitForCompletion(10, &lEvCode);

} while(lEvCode == 0);

pEvent->Release();
}
}


void main (int argc, char *argv[])
{

WCHAR SourceFile[MAX_PATH];

IGraphBuilder *pGraph = NULL;
IMediaControl *pControl = NULL;
IMediaEvent *pEvent = NULL;

// Initialize the COM library.
HRESULT hr = CoInitialize(NULL);
if (FAILED(hr))
{
printf("ERROR - Could not initialize COM library");
return;
}

// Create the filter graph manager and query for interfaces.
hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
IID_IGraphBuilder, (void **)&pGraph);
if (FAILED(hr))
{
printf("ERROR - Could not create the Filter Graph Manager.");
return;
}

hr = pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl);
hr = pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent);

MultiByteToWideChar(CP_ACP, 0, argv[1], -1, SourceFile, NUMELMS(SourceFile));
// Build the graph. IMPORTANT: Change this string to a file on your system.
hr = pGraph->RenderFile(SourceFile, NULL);
if (SUCCEEDED(hr))
{
// Run the graph.
hr = pControl->Run();
if (SUCCEEDED(hr))
{

WaitForCompletion(pGraph);
}
}
pControl->Release();
pEvent->Release();
pGraph->Release();
CoUninitialize();
}

Я в него добавил функцию WaitForCompletion, так как в примере от Microsoft не рекомендуется использовать в реальной жизни
// Note: Do not use INFINITE in a real application, because it
// can block indefinitely. »
Взял её из того же найденного проекта ( http://csclab.murraystate.edu/bob.pilgrim/info/game_stuff/DirectX%20(C++)/Samples/C++/DirectShow/Misc/ASFCopy/asfcopy.cpp).

ivank, pva премного благодарен.




© OSzone.net 2001-2012