4字符串字符串和FourCC(又名OSType)值可以和平与和谐共存吗?

时间:2013-11-30 15:56:18

标签: delphi

我正在使用RIFFCHUNK结构,在(外国“模块中)声明为(引用MMSystemDirectShow9):

  type FOURCC = DWORD;                    { a four character code }

  type _riffchunk = record
    fcc: FOURCC;
    cb: DWORD;
  end;
  type RIFFCHUNK = _riffchunk;

我特别感兴趣的是fcc字段,该字段解析为LongWord。另一方面,fcc的有意义值是由4个ASCII可打印单字节字符组成的字符串。我想避免以下丑陋(引用MMSystem):

  const FOURCC_RIFF = $46464952;   { 'RIFF' }

...并使用实际的,自解释的四个字符串文字进行分配和比较。

到目前为止,我尝试了什么并且卡在了下面:

const idRIFF: packed array [1..4] of AnsiChar = 'RIFF';
var Chunk: RIFFCHUNK;
begin
  Chunk.fcc := FOURCC(idRIFF);  { works, but requires a typecast in implementation }

由于idRIFF不是真常量,因此不能用于正确输入符号的声明。

那么,我想问一下这个美化事件的进一步建议?

请注意FOURCC类型为“foreign”,因此我不能将其重新声明为字符数组。

4 个答案:

答案 0 :(得分:4)

此声明将使用字符串文字将FOURCC_RIFF视为常量:

const
  FOURCC_RIFF_S : array[0..SizeOf(FOURCC)-1] of AnsiChar = 'RIFF';
var
  FOURCC_RIFF : FOURCC absolute FOURCC_RIFF_S;

如果启用了可写常量指令,那么也可以通过捕获编译器指令来修复。

{$IFOPT J+}
  {$DEFINE UNDO_WRCONST}
  {$J-}
{$ENDIF}
const
  FOURCC_RIFF_S : array[0..SizeOf(FOURCC)-1] of AnsiChar = 'RIFF';
var
  FOURCC_RIFF : FOURCC absolute FOURCC_RIFF_S;
{$IFDEF UNDO_WRCONST}
  {$J+}
{$ENDIF}

不需要进行类型转换,编译器会将该值视为真常量。

var
  Chunk: RIFFCHUNK;
...
  Chunk.fcc := FOURCC_RIFF;

答案 1 :(得分:2)

你也可以写:

_riffchunk.fcc := PCardinal(PAnsiChar('RIFF'))^;

是的,它有效!

这实际上与写作相同:

const
  FOURCC_RIFF: PAnsiChar = 'RIFF';
...
  _riffchunk.fcc := PCardinal(FOURCC_RIFF)^;

因此,您可以使用以下功能:

function ToFourCC(const s: AnsiString): FOURCC; inline;
begin
  result := PCardinal(s)^;
end;

_riffchunk.fcc := ToFourCC('RIFF');

当然,所有这些都不能与NextGen编译器一起使用。

答案 2 :(得分:2)

多媒体API定义了MAKEFOURCC()mmioFOURCC()个宏,这两个宏都将4个字符转换为FOURCC值,例如:

Chunk.fcc := MAKEFOURCC('R', 'I', 'F', 'F'); 

Chunk.fcc := mmioMAKEFOURCC('R', 'I', 'F', 'F'); 

如果Delphi在MMSystem单元中没有现有的翻译(它应该,但我现在无法检查),这里有一个:

function MAKEFOURCC(ch0, ch1, ch2, ch3: AnsiChar): LongWord;
begin
  Result := LongWord(Ord(ch0)) or (LongWord(Ord(ch1)) shl 8) or (LongWord(Ord(ch2)) shl 16) or (LongWord(Ord(ch3)) shl 24); 
end;

答案 3 :(得分:1)

我想不出比助手功能更好的东西:

function FourCCfromString(const Value: AnsiString): FOURCC;
begin
  if Length(Value)<>SizeOf(Result) then
    raise ESomeException.Create(...);
  Move(Pointer(Value)^, Result, SizeOf(Result));
end;

我能看到的好处是:

  1. 呼叫站点没有投射。所有的肮脏都被封装在帮手中。
  2. 无需声明任何新类型 - 您可以使用普通旧字符串。

  3. 我认为你不能在这里使用带有类操作符的记录助手。您无法在记录助手中定义类操作符。

    您可以使用Implicit类运算符定义记录以执行转换。它看起来像这样:

    type
      TMyFourCC = record
        Value: FOURCC;
        class operator Implicit(const Value: AnsiString): TMyFourCC;
        class operator Implicit(const Value: string): TMyFourCC;
        class operator Implicit(const Value: TMyFourCC): FOURCC;
      end;
    

    但是你需要写:

    Chunk.fcc := 'RIFF'; 
    

    并且无法编译,因为编译器无法推断您希望从string转到TMyFourCC然后转到FOURCC。不幸的是,隐式转换运算符只允许单跳。