Наконец-то у меня появилось время обновить класс захвата видео. Я хотел сравнить VFW (что я использовал до сих пор) и DirectShow. Как и ожидалось, DirectShow быстрее, но когда я добавил информационные тексты, вдруг AnsiString::sprint()
больше не является членом AnsiString
,
После некоторой борьбы я нашел обходной путь как AnsiString::printf()
все еще работает, но мне любопытно, как это исправить. Может быть, некоторые определяют из dshow.h
а также dstring.h
противоречивы?
Я сократил весь ненужный код, чтобы показать эту проблему:
//$$---- Form CPP ----
//---------------------------------------------------------------------------
#include <vcl.h>
#include <dshow.h>
#pragma hdrstop
#include "Unit1.h"//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
static int i=0;
Caption=AnsiString().sprintf("%i",i); // this does not work
AnsiString s; s.printf("%i",i); Caption=s; // this does work
i++;
}
//---------------------------------------------------------------------------
Это просто приложение VCL Form с одним TTimer
в теме. TTimer
увеличивает счетчик i
и вывести его в форме Caption
, DirectX libs даже не связаны, только заголовки включены!
Линкер выводит ошибку:
[C++ Error] Unit1.cpp(20): E2316 'sprintf_instead_use_StringCbPrintfA_or_StringCchPrintfA' is not a member of 'AnsiString'
Если я поменяю vcl.h
и dshow.hincludes, the compiler stops in
dstring.h` в этой строке:
AnsiString& __cdecl sprintf(const char* format, ...); // Returns *this
С этим сообщением об ошибке:
[C++ Error] dstring.h(59): E2040 Declaration terminated incorrectly
Таким образом, существует определенный конфликт ( AnsiString
Ключевое слово является проблемой). Ввод dshow.h
в namespace
тоже не помогает.
У кого-нибудь есть какие-нибудь подсказки?
Q1. Как это исправить?
Q2. Что / где именно это вызывает?
Единственное решение, о котором я могу думать и которое должно работать (но я хочу избежать этого, если смогу), — это создать OBJ (или же DLL) с DirectShow вещи, а затем связать это в стандарт VCL проект без включения dshow.h
в этом, и, конечно, экспорт должен быть без каких-либо забавных вещей, тоже.
Проблема не с dshow.h
сам, но на самом деле с strsafe.h
вместо этого, который dshow.h
включает по умолчанию.
strsafe.h
содержит следующий код 1:
#ifndef STRSAFE_NO_DEPRECATE
// Deprecate all of the unsafe functions to generate compiletime errors. If you do not want
// this then you can #define STRSAFE_NO_DEPRECATE before including this file
#ifdef DEPRECATE_SUPPORTED
...
#pragma deprecated(sprintf)
...
#else // DEPRECATE_SUPPORTED
...
#undef sprintf
#define sprintf sprintf_instead_use_StringCchPrintfA_or_StringCbPrintfA;
...
#endif // DEPRECATE_SUPPORTED
#endif // !STRSAFE_NO_DEPRECATE
1 Есть похожие #pragma
а также #define
операторы для многих других устаревших «небезопасных» функций C.
Если оба STRSAFE_NO_DEPRECATE
а также DEPRECATE_SUPPORTED
не определены (что имеет место в данной ситуации), использование #define sprintf
причины все последующие ссылки на любой из sprintf
условное обозначение быть замеченным как sprintf_instead_use_StringCchPrintfA_or_StringCbPrintfA;
во время компиляции.
Вот почему вы получаете ошибку компилятора. когда vcl.h
включен до strsafe.h
, dstring.h
включается первым, поэтому компилятор видит правильный декларация для AnsiString::sprintf()
метод, а затем strsafe.h
включается (предположительно Unit1.h
) прежде чем компилятор увидит ваш Timer1Timer()
код, так что ваши звонки AnsiString().sprint("%i",i)
на самом деле пытаются позвонить AnsiString().sprintf_instead_use_StringCchPrintfA_or_StringCbPrintfA;("%i",i)
, которые терпят неудачу.
Когда вы меняете vcl.h
а также dshow.h
включает в себя, #define sprintf
заявление в strsafe.h
обрабатывается раньше dstring.h
включен, поэтому компилятор видит следующее объявление для AnsiString::sprintf()
метод в dstring.h
и не удается:
AnsiString& __cdecl sprintf_instead_use_StringCchPrintfA_or_StringCbPrintfA;(const char* format, ...); // Returns *this
Чтобы предотвратить такое поведение, вы мог использовать #undef sprintf
заявление после #include <dshow.h>
как предложил Джеффрсон. Тем не менее правильный Решение состоит в том, чтобы определить STRSAFE_NO_DEPRECATE
до #include <strsafe.h>
, Вы можете сделать это одним из следующих способов:
добавление #define STRSAFE_NO_DEPRECATE
в ваш код до #include <dshow.h>
заявление
добавление STRSAFE_NO_DEPRECATE
в список Условий в опциях вашего проекта.
Это решение описано в MSDN:
Когда вы включаете в свой файл Strsafe.h, более старые функции, замененные функциями Strsafe.h, будут устаревшими. Попытки использовать эти старые функции приведут к ошибке компилятора, говорящей вам использовать более новые функции. Если вы хотите переопределить это поведение, включите следующий оператор перед включением Strsafe.h.
#define STRSAFE_NO_DEPRECATE
Чтобы разрешить только функции подсчета символов, включите следующий оператор перед тем, как включать Strsafe.h.
#define STRSAFE_NO_CB_FUNCTIONS
Чтобы разрешить только функции подсчета байтов, перед включением Strsafe.h включите следующую инструкцию.
#define STRSAFE_NO_CCH_FUNCTIONS
Другое поддерживаемое решение — определить NO_DSHOW_STRSAFE
до #include <dshow.h>
так что это не будет включать strsafe.h
больше, благодаря этому коду в dshow.h
:
#ifndef NO_DSHOW_STRSAFE
#define NO_SHLWAPI_STRFCNS
#include <strsafe.h>
#endif
У меня нет этой самой версии dshow.h и dstring.h, поэтому я не могу проверить это сам, но из сообщений об ошибках, которые вы цитируете, кажется, что где-то в dshow.h или его зависимостях они объявляют макрос «sprintf». Вы можете посмотреть, если вы можете найти это.
Чтобы предотвратить такое поведение, вам нужно удалить этот макрос. использование
#undef sprintf
после строки, включающей dshow.h.