2010-05-31 12 views

Respuesta

12

Esto es para compatibilidad con versiones anteriores cuando se extiende la API de Windows.

Imagine las siguientes declaraciones

struct WinData 
{ 
    long flags; 
} 
BOOL GetWinData(WinData * wd); 

que realiza la llamada como esto:

WinData wd; 
GetWinData(&wd); 

Una versión futura del sistema operativo puede extender esto a

struct WinData 
{ 
    long flags; 
    long extraData; 
} 

Sin embargo, si ha compilado en contra del SDK "anterior", GetWinData no tiene ninguna posibilidad de descubrir que usted no sabe aproximadamente extraData. Si lo llenase independientemente, sobrescribiría los datos en la pila. ¡BOOOM!

Por eso, el "tamaño conocido por la persona que llama" se agrega a la estructura y los miembros nuevos se anexan al final. La implementación de GetWinData puede inspeccionar el tamaño y decidir "este pobre tipo aún no conoce todas las características nuevas".

+2

+1 Debe haber un sitio web dedicado a las razones por las que las personas piensan que Windows es una mierda, junto con explicaciones racionales y sensatas (como esta) sobre por qué algo se hace de cierta manera. También es interesante cómo la compatibilidad con versiones anteriores es a menudo la explicación de algo extraño en Windows. Utilizo esto para silenciar a los fanboys de Mac a veces, recordándoles cómo todo el software deja de funcionar con cada nuevo sistema operativo. – MusiGenesis

+0

A veces usan el tamaño o la variable de versión, a veces van a somestructEx para indicar extra o extendido. –

+11

@MusiGenesis: creo que hay un sitio web de este tipo y se llama [Raymond Chen's Blog] (http://blogs.msdn.com/b/oldnewthing/). :-) –

8

Esto es para que la estructura se puede ampliar en futuras versiones de la API, y Windows se puede saber (por el tamaño de la persona que llama aprobada en) qué campos debe ser visto o no. Básicamente es una forma cruda de versiones de API.

Por lo general, esos bytes de conteo tienen el prefijo cb, que significa "recuento de bytes". Por ejemplo, la estructura STARTUPINFO comienza con:

typedef struct _STARTUPINFO { 
    DWORD cb; 
    LPTSTR lpReserved; 
    ... 
} STARTUPINFO, *LPSTARTUPINFO; 

Esto se extendió en algún momento con la estructura STARTUPINFOEX, que contiene la misma primera parte pero de un tamaño diferente. Según el valor de cb, Windows sabrá si desea o no mirar el nuevo campo lpAttributeList.

+2

¿Funcionan otros sistemas operativos principales con versiones de API de esta manera, o hay mejores alternativas en uso? – MusiGenesis

+0

@MusiGenesis: buena pregunta, pregunte :) – MSalters

0

Para que las futuras versiones pueden añadir campos adicionales y aún así ser capaz de proporcionar compatibilidad binaria hacia atrás:

// CAUTION - the code is not 100% accurate and can fail due to packing rules. 
// For illustrative purposes only 
if (offsetof(struct foo, field) > f->pbFormat) 
{ 
    // called with a version that predates the addition of 
    // field so revert to a default value 
} 
+0

En realidad no puede fallar debido a las reglas de embalaje, ya que están implícitos en Win32. – MSalters

+0

@MSalters: lamentablemente, puede fallar. Considere comenzar con 'struct foo {int size; corto s1; char c1; } 'y luego extender eso a' struct foo {int size; corto s1; char c1; char c2; } 'Ambos tendrán tamaño 8, por lo que no podrás saber si la persona que llama tiene una definición con o sin el campo' c2'. –

+0

Según las reglas de Win32, esa no es una forma válida de definir la versión 2 de 'struct foo'. El primer DWORD, establecido en sizeof (objeto), debe ser diferente entre v1 y v2. – MSalters

1

El PB es un ejemplo de Hungarian Notation, básicamente un esquema para codificar un tipo de variable en su nombre.

+0

Creo que la pregunta no está dirigida a la convención de nomenclatura – YeenFei

+0

Aunque esta es una buena ilustración incidental del problema principal con la notación húngara: si comienzas a contar con esas pequeñas letras para significar realmente * algo importante, estás en problemas. – MusiGenesis

+0

En realidad, los dos caracteres 'cb' indican algo que su IDE no: número de bytes. – CMircea

1

Porque la API de Win32 es C API, no C++, por lo que los métodos orientados a objetos para extender la API no están disponibles. Con la API C++, una nueva característica usaría una estructura que deriva de la anterior y llamaría a una interfaz que tome la estructura base, asegurando la seguridad del tipo.

C es un lenguaje de procedimiento y está más limitado en lo que se puede hacer con las estructuras.

Cuestiones relacionadas