2016-10-12 9 views
1

Наконец-то я получил некоторое время, чтобы обновить класс видеозахвата. Я хотел сравнить VFW (что я использовал до сих пор) и DirectShow. Как и ожидалось, DirectShow быстрее, но когда я добавил информационные тексты, вдруг AnsiString::sprint() больше не является членом AnsiString.Включая DShow.h breaks VCL AnsiString :: sprintf() на BDS2006

После некоторой борьбы я нашел обходное решение, так как 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.h includes, the compiler stops in dstring.h` на этой линии:

AnsiString& __cdecl   sprintf(const char* format, ...); // Returns *this 

С этим сообщением об ошибке:

[C++ Error] dstring.h(59): E2040 Declaration terminated incorrectly 

Итак, есть определенный конфликт (ключевое слово AnsiString равно t он проблема). Помещение dshow.h в namespace тоже не помогает.

У кого-нибудь есть ключи?

Q1. Как это исправить?

Q2. Что/где именно это вызывает?

Единственное решение, которое я могу думать, и должен работать (но я хочу, чтобы избежать этого, если я могу), чтобы создать OBJ (или DLL) с DirectShow вещи, и затем свяжите это со стандартным проектом VCL без включения в него dshow.h, и, конечно же, экспорт должен быть без каких-либо забавных вещей.

+1

попробуйте "#undef sprintf" после включения dshow.h – JeffRSon

+1

@JeffRSon да, это работает, чтобы ответить, поэтому я могу принять его странно, поскольку VCL включен до DShow ... но он работает – Spektre

ответ

1

Проблема не с dshow.h сама, но на самом деле с strsafe.h, которая dshow.h включает в себя по умолчанию.

strsafe.h содержит следующий код :

#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 

Есть аналогичные #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>, как предположил JeffRSon. Однако correct решение должно определять STRSAFE_NO_DEPRECATE до #include <strsafe.h>. Вы можете сделать это либо:

  1. добавление #define STRSAFE_NO_DEPRECATE в код перед #include <dshow.h> заявлением

  2. добавления STRSAFE_NO_DEPRECATE в список ваших условий в Параметрах проекта.

Это решение описано в MSDN:

About Strsafe.h

  • When you include Strsafe.h in your file, the older functions replaced by the Strsafe.h functions will be deprecated. Attempts to use these older functions will result in a compiler error telling you to use the newer functions. If you want to override this behavior, include the following statement before including Strsafe.h.

    #define STRSAFE_NO_DEPRECATE 
    
  • To allow only character count functions, include the following statement before including Strsafe.h.

    #define STRSAFE_NO_CB_FUNCTIONS 
    
  • To allow only byte count functions, include the following statement before including 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 
+0

Спасибо за прояснение ... – Spektre

1

У меня нет такой версии dshow.h и dstring.h, поэтому я не могу ее проверить сам, но из сообщений об ошибках, которые вы цитируете, кажется, что где-то в dshow.h или его зависимостях они объявляют " sprintf ". Вы можете посмотреть, сможете ли вы его найти.

Чтобы предотвратить это поведение, вам необходимо удалить этот макрос. Использовать

#undef sprintf 

после строки, которая включает dshow.h.

+0

Спасибо, много крутится в часах ... – Spektre

+0

Иногда странно, SDK и vcl влияют друг на друга. Это dshow.h от BDS2006? Я помню, как только мне пришлось #undef StrToInt ... – JeffRSon

+0

Да, это из BDS2006 Turbo C++ Explorer. Связанный 'strmiids.lib' является версией DirectX9.2 (версия BCB) и работает. Я не так привык к использованию DirectX только DInput, а в прошлом также и к DSound, но это был перебор, поскольку он был непригодным из-за латентности и неработающих обратных вызовов в то время ... Но повеселимся с некоторыми источниками стиля MSVC++ в BCB и некоторые из них включают mes из определений и включают порядок ... – Spektre