2010-08-14 6 views
3

Je viens de lire this question et this question, et depuis, j'ai essayé d'appeler SHGetSetSettings en Delphi. Ceci est une fonction de shell32.dll, mais n'est pas définie dans ShlObj.pas, nous devons donc écrire notre propre définition.Appeler SHGetSetSettings à partir de Delphi

Nous devons d'abord traduire la structure SHELLSTATE. Maintenant, je n'ai qu'une expérience limitée en C, mais je suppose que ": 1" signifie que le membre de la structure est un seul bit, c'est-à-dire que huit d'entre eux peuvent être emballés ensemble dans un octet. Je suppose également que DWORD = UINT = entiers non signés de 32 bits et que LONG = int sont des entiers signés de 32 bits. Mais alors nous avons un problème: la structure entière occupera alors 228 bits, soit 28,5 octets, ce qui est plutôt impossible, du moins en Delphi, où sizeof(SomeRecord) doit être un entier.

Néanmoins, j'ai essayé de le résoudre en ajoutant quatre bits fictifs à la fin. 232 bits = 29 octets, ce qui est bien.

D'où j'ai essayé

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; 

puis je déclare (pour plus de commodité plus tard)

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; 

Maintenant, je me sentais prêt à définir

interface 
    procedure SHGetSetSettings(var ShellState: TShellState; Mask: cardinal; DoSet: boolean); stdcall; 

implementation 
    procedure SHGetSetSettings; external shell32 name 'SHGetSetSettings'; 

Mais avant d'essayer le code, J'ai remarqué quelque chose de très étrange. J'ai trouvé que les constantes que j'ai déclarées étaient déjà déclarées ici: SSF Constants. Notez que SSF_HIDEICONS = 0x00004000 = 16384 ≠ fHideIcons = 4096. Si les constantes SSF_ sont vraiment des masques utilisés avec SHELLSTATE, alors cela n'a aucun sens de définir SSF_HIDEICONS comme 2^14 quand c'est le 13ème bit (et son masque devrait être 2^12) dans la structure. Il semble donc que les deux pages de référence MSDN se contredisent.

Quelqu'un pourrait-il clarifier tout cela?

Répondre

3

Ma lecture de l'aide ici est que les constantes SSF_ sont spécifiées pour le masque lors de la récupération des données. Il n'y a aucune raison pour qu'ils soient mappés aux bits de la structure ShellState.

S'ils ont fait fShowSysFiles serait mappé à 8 (0x04), et nous savons de l'aide que SSF_SHOWSYSFILES est 0x20. Il n'y a pas de cartographie directe.

+0

Oui, bien sûr, ils n'ont pas * besoin * de cartographier les bits de la structure. Mais il semblait si raisonnable à l'époque! –

+0

Mais qu'en est-il de l'autre problème: est-il possible pour une structure C de ne pas avoir un nombre entier d'octets comme sa taille? –

+0

Non. En regardant la déclaration, les champs de bits sont spécifiés comme étant dans un BOOL, donc le type sous-jacent est int. Je fais la taille de cette structure 36 octets, en un coup d'oeil. Bien sûr, struct packing peut modifier la taille, mais puisque tout ici (int, UINT, long, DWORD) est de 4 octets sur un OS 32 bits, je pense que l'estimation est raisonnablement sûre. Bien sûr, certains juristes vont sauter ici et me prouver que je me trompe :-). Méfiez-vous si vous travaillez avec un compilateur 64 bits si ... cette valeur va changer. –

0

Les champs de bits Afaik dans C sont un sous-type d'entier. Il y a des façons de l'empaqueter, mais aussi en C, après un tas de champs à un seul bit, il y aura un remplissage à la prochaine octet (et probablement même à la suivante). De plus, sizeof de C ne supporte pas non plus les moitiés.

Donc, il est probablement 1 + 6 + 1 fois sizeof (entier) = 32 octets.

1

Voici la définition TShellState dans 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} 

Pas très utile, malheureusement.

+0

Eh bien, c'est vraiment * très * utile. Entre autres, ceci indique que tous les BOOL: 1 occupent huit octets ensemble. Un peu bizarre, cependant, parce que 17 bits peuvent tenir dans trois octets, donc un cardinal aurait été suffisant. Btw: Je suppose qu'un UINT est un entier non signé, c'est-à-dire un cardinal, comme DWORD. Mais pourquoi deux "alias" différents sont-ils utilisés? Hm ... Il me semble que je n'ai que 24 octets ... –

2

La déclaration D2010 de SHELLSTATE dans ShlObj.pas est malheureusement incorrecte, mais le premier groupe de bits (17) correspond correctement à Data: DWORD; (le tien est en effet OK). Il pourrait y en avoir 18 ou 19 tout de même. Ensuite, nous devrions obtenir 2 DWORD/UINT supplémentaires pour les 2 Win95unused, et pas seulement Data2.

Dommage car les drapeaux SSF et les déclarations SHGetSetSettings sont déjà effectuées et correctes.

La déclaration correcte selon MSDN devrait être l'OMI:

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; 

Vous pouvez vérifier que cela permet d'obtenir les propriétés de tri correctement:

var 
    lpss: tagSHELLSTATEW; 
begin 
    ZeroMemory(@lpss, SizeOf(lpss)); 
    SHGetSetSettings(lpss, SSF_SORTCOLUMNS, False); 
+0

Oui, maintenant nous avons la bonne taille. –

0

Je suis un peu en retard à la parti, mais this article explique bitsfields assez bon et a quelques approches pour Delphi.

Questions connexes