1

我终于有时间升级我的视频捕捉课程。我想比较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并将其输出到表单的Caption. DirectX库甚至没有链接,只是包含头文件!

链接器输出错误:

[C++ Error] Unit1.cpp(20): E2316 'sprintf_instead_use_StringCbPrintfA_or_StringCchPrintfA' is not a member of 'AnsiString'

如果我在这一行交换vcl.h和 dshow.h dstring.h`:includes, the compiler stops in

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

使用此错误消息:

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

因此,显然存在一些冲突(AnsiString关键字是问题)。放入dshow.hanamespace也无济于事。

有没有人有任何线索?

Q1。如何解决这个问题?

Q2。究竟是什么/哪里导致了这种情况?

我能想到并且应该工作的唯一解决方案(但如果可以的话,我想避免它)是用DirectShow的东西创建一个OBJ(或DLL),然后将它链接到一个标准的VCL项目中,而不包括在它,当然出口也必须没有任何有趣的东西。dshow.h

4

2 回答 2

1

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

为了防止这种行为,您需要删除此宏。利用

#undef sprintf

在包含 dshow.h 的行之后。

于 2016-10-12T13:53:56.587 回答
1

问题不在于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;在编译期间。

这就是您收到编译器错误的原因。when vcl.his included before strsafe.hdstring.h首先被包含,因此编译器会看到该方法的正确声明AnsiString::sprintf(),然后在编译器看到您的代码之前strsafe.h被包含(可能是 by ),因此您的调用实际上是在尝试调用 call ,但失败了。Unit1.hTimer1Timer()AnsiString().sprint("%i",i)AnsiString().sprintf_instead_use_StringCchPrintfA_or_StringCbPrintfA;("%i",i)

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

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

为了防止这种行为,您可以在 之后使用#undef sprintf语句#include <dshow.h>,就像 JeffRSon 建议的那样。但是正确的解决方案是定义STRSAFE_NO_DEPRECATEbefore #include <strsafe.h>。您可以通过以下任一方式做到这一点:

  1. 在语句之前添加#define STRSAFE_NO_DEPRECATE到您的代码中#include <dshow.h>

  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
    

另一个受支持的解决方案是在NO_DSHOW_STRSAFE之前定义#include <dshow.h>,使其不再包含strsafe.h,这要归功于以下代码dshow.h

#ifndef NO_DSHOW_STRSAFE
#define NO_SHLWAPI_STRFCNS
#include <strsafe.h>  
#endif
于 2016-11-18T01:44:40.857 回答