包括DShow.h打破了BDS2006上的VCL AnsiString::sprintf()

Including DShow.h breaks VCL AnsiString::sprintf() on BDS2006

本文关键字:AnsiString VCL sprintf 上的 BDS2006 DShow 包括      更新时间:2023-10-16

我终于有时间升级我的视频捕捉类。我想比较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表单应用程序与一个单一的TTimer在它。TTimer将计数器i加1,并将其输出到表单的Caption中。DirectX库甚至没有链接,只是包含头文件!

链接器输出错误:

[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。到底是什么/在哪里造成的?

我能想到的唯一解决方案,应该工作(但我想避免它,如果我可以),是创建一个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对于许多其他已弃用的"不安全"C函数,有类似的#pragma#define语句。

如果STRSAFE_NO_DEPRECATEDEPRECATE_SUPPORTED都没有定义(在这种情况下),使用#define sprintf会导致所有后续对任何类型的 sprintf符号的引用在编译过程中被视为sprintf_instead_use_StringCchPrintfA_or_StringCbPrintfA;

这就是为什么你得到编译器错误。当vcl.hstrsafe.h之前包含时,dstring.h首先被包含,因此编译器看到AnsiString::sprintf()方法的正确的声明,然后在编译器看到Timer1Timer()代码之前包含strsafe.h(可能是Unit1.h),因此您对AnsiString().sprint("%i",i)的调用实际上试图调用AnsiString().sprintf_instead_use_StringCchPrintfA_or_StringCbPrintfA;("%i",i),失败。

当您交换vcl.hdshow.h包含时,strsafe.h中的#define sprintf语句在dstring.h包含之前被处理,因此编译器看到dstring.hAnsiString::sprintf()方法的以下声明并失败:

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

为了防止这种行为,你可以#include <dshow.h>之后使用#undef sprintf语句,就像JeffRSon建议的。然而,正确的解决方案是在#include <strsafe.h>之前定义STRSAFE_NO_DEPRECATE。你可以这样做:

  1. #include <dshow.h>语句之前添加#define STRSAFE_NO_DEPRECATE

  2. STRSAFE_NO_DEPRECATE添加到项目选项的条件列表中

此解决方案在MSDN上描述:

关于Strsafe.h

  • 当你在文件中包含Strsafe.h时,被Strsafe.h函数取代的旧函数将被弃用。尝试使用这些较旧的函数将导致编译器错误,告诉您使用较新的函数。如果您想覆盖此行为,请在包含Strsafe.h之前包含以下语句。

    #define STRSAFE_NO_DEPRECATE
    
  • 要只允许字符计数函数,在包含Strsafe.h之前包含以下语句。

    #define STRSAFE_NO_CB_FUNCTIONS
    
  • 要只允许字节计数函数,在包含Strsafe.h之前包含以下语句。

    #define STRSAFE_NO_CCH_FUNCTIONS
    

另一个支持的解决方案是在#include <dshow.h>之前定义NO_DSHOW_STRSAFE,这样它将不再包含strsafe.h,感谢dshow.h中的这段代码:

#ifndef NO_DSHOW_STRSAFE
#define NO_SHLWAPI_STRFCNS
#include <strsafe.h>  
#endif

我没有dshow.h和string.h的这个版本,所以我不能自己检查,但从你引用的错误消息中,似乎在dshow.h或其依赖项的某个地方声明了一个"sprintf"宏。如果你能找到它,你可以看看。

为了防止这种行为,你需要删除这个宏。使用

#undef sprintf