c - Llamar a SHGetSetSettings desde Delphi
winapi translation (5)
Acabo de leer esta pregunta y esta pregunta , y desde entonces he estado intentando llamar a SHGetSetSettings
en Delphi. Esta es una función de shell32.dll
, pero no está definida en ShlObj.pas
, por lo que debemos escribir nuestra propia definición.
Primero tenemos que traducir la estructura SHELLSTATE
. Ahora solo tengo una experiencia limitada en C, pero supongo que ": 1" significa que el miembro de la estructura es un bit único, es decir, que ocho de ellos pueden agruparse en un byte. También supongo que DWORD
= UINT
= enteros sin signo de 32 bits y que LONG
= int
son enteros de 32 bits con signo. Pero entonces tenemos un problema: toda la estructura ocupará 228 bits, o 28.5 bytes, lo que es ... más bien imposible, al menos en Delphi, donde sizeof(SomeRecord)
tiene que ser un número entero.
Sin embargo, traté de resolverlo agregando cuatro bits falsos al final. 232 bits = 29 bytes, lo cual es bueno.
Por eso probé
PShellState = ^TShellState;
TShellState = packed record
Data1: cardinal;
Data2: cardinal;
Data3: cardinal;
Data4: cardinal;
Data5: cardinal;
Data6: cardinal;
Data7: cardinal;
Data8: byte; // Actually a nibble would be sufficient
end;
y luego declare (para mayor conveniencia)
const
fShowAllObjects = 1;
fShowExtensions = 2;
fNoConfirmRecycle = 4;
fShowSysFiles = 8;
fShowCompColor = 16;
fDoubleClickInWebView = 32;
fDesktopHTML = 64;
fWin95Classic = 128;
fDontPrettyPath = 256;
fShowAttribCol = 512;
fMapNetDrvButton = 1024;
fShowInfoTip = 2048;
fHideIcons = 4096;
fWebView = 8192;
fFilter = 16384;
fShowSuperHidden = 32768;
fNoNetCrawling = 65536;
Ahora me sentí listo para definir
interface
procedure SHGetSetSettings(var ShellState: TShellState; Mask: cardinal; DoSet: boolean); stdcall;
implementation
procedure SHGetSetSettings; external shell32 name ''SHGetSetSettings'';
Pero antes de probar el código, noté algo muy extraño. Descubrí que las constantes que declaraba ya estaban declaradas aquí: Constantes SSF . Observe que SSF_HIDEICONS = 0x00004000 = 16384 ≠ fHideIcons = 4096
. Si las constantes SSF_
son realmente máscaras usadas junto con SHELLSTATE
, entonces no tiene sentido definir SSF_HIDEICONS
como 2 ^ 14 cuando es el 13er bit (y su máscara debe ser 2 ^ 12) en la estructura. Por lo tanto, parece que las dos páginas de referencia de MSDN se contradicen entre sí.
¿Podría alguien aclarar algo de todo esto?
Aquí está la definición de TShellState en Delphi 2010:
type
tagSHELLSTATEW = record
Data: DWORD;
Data2: UINT;
{ fShowAllObjects: BOOL:1;
fShowExtensions: BOOL:1;
fNoConfirmRecycle: BOOL:1;
fShowSysFiles: BOOL:1;
fShowCompColor: BOOL:1;
fDoubleClickInWebView: BOOL:1;
fDesktopHTML: BOOL:1;
fWin95Classic: BOOL:1;
fDontPrettyPath: BOOL:1;
fShowAttribCol: BOOL:1;
fMapNetDrvBtn: BOOL:1;
fShowInfoTip: BOOL:1;
fHideIcons: BOOL:1;
fWebView: BOOL:1;
fFilter: BOOL:1;
fShowSuperHidden: BOOL:1;
fNoNetCrawling: BOOL:1;}
//dwWin95Unused: DWORD;// Win95 only - no longer supported pszHiddenFileExts
//uWin95Unused: UINT; // Win95 only - no longer supported cbHiddenFileExts
// Note: Not a typo! This is a persisted structure so we cannot use LPARAM
lParamSort: Integer;
iSortDirection: Integer;
version: UINT;
// new for win2k. need notUsed var to calc the right size of ie4 struct
// FIELD_OFFSET does not work on bit fields
uNotUsed: UINT;// feel free to rename and use
{ fSepProcess: BOOL:1;
// new for Whistler.
fStartPanelOn: BOOL:1;
fShowStartPage: BOOL:1;
// new for Windows Vista
fAutoCheckSelect: BOOL:1;
fIconsOnly: BOOL:1;
fShowTypeOverlay: BOOL:1;
// If you need a new flag, steal a bit from from fSpareFlags.
// Also, keep SHELLFLAGSTATE and SHGetSettings in sync when adding new flags.
fSpareFlags: UINT:11;
}
end;
{$EXTERNALSYM tagSHELLSTATEW}
SHELLSTATEA = tagSHELLSTATEW;
{$EXTERNALSYM SHELLSTATEA}
SHELLSTATEW = tagSHELLSTATEW;
{$EXTERNALSYM SHELLSTATEW}
SHELLSTATE = SHELLSTATEW;
{$EXTERNALSYM SHELLSTATE}
TShellState = SHELLSTATE;
PShellState = ^TShellState;
const
SHELLSTATEVERSION_IE4 = 9;
{$EXTERNALSYM SHELLSTATEVERSION_IE4}
SHELLSTATEVERSION_WIN2K = 10;
{$EXTERNALSYM SHELLSTATEVERSION_WIN2K}
No es muy útil, desafortunadamente.
Los bitfields de Afaik en C son un subtipo de entero. Hay formas de empaquetarlo, pero también en C, después de un montón de campos de un solo bit, habrá espacio para el próximo byte boundery (y probablemente incluso para el próximo entero Boundery). Además, el tamaño de C no es compatible con las mitades.
Entonces probablemente sea 1 + 6 + 1 veces sizeof (integer) = 32bytes.
Mi lectura de la ayuda aquí es que las constantes SSF_ se especifican para la máscara cuando se recuperan datos. No hay razón para que tengan que mapear los bits en la estructura ShellState.
Si lo hicieran, fShowSysFiles se correlacionaría con 8 (0x04), y sabemos por la ayuda que SSF_SHOWSYSFILES es 0x20. No hay mapeo directo.
La declaración D2010 de SHELLSTATE en ShlObj.pas desafortunadamente es incorrecta, pero el primer grupo de bits (17) coincide correctamente con Data: DWORD;
(El tuyo está de hecho bien). Podría haber 18 o 19 de ellos todos iguales. Entonces deberíamos obtener 2 DWORD / UINT más para el 2 Win95unused, no solo Data2.
Es una lástima porque las banderas SSF y las declaraciones SHGetSetSettings ya están hechas allí y son correctas.
La declaración correcta de acuerdo con MSDN debe ser IMO:
tagSHELLSTATEW = record
Data: DWORD;
{ fShowAllObjects: BOOL:1;
fShowExtensions: BOOL:1;
fNoConfirmRecycle: BOOL:1;
fShowSysFiles: BOOL:1;
fShowCompColor: BOOL:1;
fDoubleClickInWebView: BOOL:1;
fDesktopHTML: BOOL:1;
fWin95Classic: BOOL:1;
fDontPrettyPath: BOOL:1;
fShowAttribCol: BOOL:1;
fMapNetDrvBtn: BOOL:1;
fShowInfoTip: BOOL:1;
fHideIcons: BOOL:1;
fWebView: BOOL:1;
fFilter: BOOL:1;
fShowSuperHidden: BOOL:1;
fNoNetCrawling: BOOL:1;}
dwWin95Unused: DWORD;// Win95 only - no longer supported pszHiddenFileExts
uWin95Unused: UINT; // Win95 only - no longer supported cbHiddenFileExts
// Note: Not a typo! This is a persisted structure so we cannot use LPARAM
lParamSort: Integer;
iSortDirection: Integer;
version: UINT;
// new for win2k. need notUsed var to calc the right size of ie4 struct
// FIELD_OFFSET does not work on bit fields
uNotUsed: UINT;// feel free to rename and use}
Data2: DWORD;
{ fSepProcess: BOOL:1;
// new for Whistler.
fStartPanelOn: BOOL:1;
fShowStartPage: BOOL:1;
// new for Windows Vista
fAutoCheckSelect: BOOL:1;
fIconsOnly: BOOL:1;
fShowTypeOverlay: BOOL:1;
// If you need a new flag, steal a bit from from fSpareFlags.
// Also, keep SHELLFLAGSTATE and SHGetSettings in sync when adding new flags.
fSpareFlag: UINT:13;}
end;
Puede verificar que esto permite obtener las propiedades de clasificación correctamente con:
var
lpss: tagSHELLSTATEW;
begin
ZeroMemory(@lpss, SizeOf(lpss));
SHGetSetSettings(lpss, SSF_SORTCOLUMNS, False);
Llego un poco tarde a la fiesta, pero este artículo explica bitfields bastante bien y tiene algunos enfoques para Delphi.