我终于有时间升级我的视频捕获类(class)。我想比较 VFW (到目前为止我使用过的)和 DirectShow 。不出所料, DirectShow 更快,但是当我添加信息文本时,突然AnsiString::sprint()不再是AnsiString的成员。

经过一番努力后,我发现一种解决方法,因为AnsiString::printf()仍然有效,但是我很好奇如何解决此问题。也许有人从dshow.hdstring.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应用程序,上面只有一个TTimerTTimer将递增计数器i并将其输出到表单的Caption中。 DirectX 库甚至没有链接,仅包含 header !

链接器输出错误:
[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关键字是问题)。将dshow.h放入namespace也无济于事。

有人有任何线索吗?

Q1。如何解决这个问题?

Q2。到底是什么/什么原因造成的?

我能想到的并且应该起作用的唯一解决方案(但如果可以的话,我想避免使用它)是使用 DirectShow 内容创建一个 OBJ (或 DLL ),然后将其链接到标准 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对于许多其他不推荐使用的“不安全” C函数,也有类似的#pragma#define语句。

如果没有同时定义STRSAFE_NO_DEPRECATEDEPRECATE_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.hdshow.h include时,在包括#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建议的那样。但是,正确的解决方案是在STRSAFE_NO_DEPRECATE之前定义#include <strsafe.h>。您可以通过以下任一方法来做到这一点:
  • #define STRSAFE_NO_DEPRECATE语句
  • 之前将#include <dshow.h>添加到您的代码中
  • 在项目选项的条件列表中添加STRSAFE_NO_DEPRECATE

  • 在MSDN上描述了此解决方案:

    About Strsafe.h



    另一个受支持的解决方案是,在NO_DSHOW_STRSAFE之前定义#include <dshow.h>,以便由于strsafe.h中的以下代码而不再包括dshow.h:
    #ifndef NO_DSHOW_STRSAFE
    #define NO_SHLWAPI_STRFCNS
    #include <strsafe.h>
    #endif
    

    关于c++ - 包括DShow.h会破坏BDS2006上的VCL AnsiString::sprintf(),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/40000171/

    10-10 21:29