Erweiterte DateiInfos auslesen (Dateikommentar)



  • Ja das sehe ich auch so, bloß stört mich die Tatsache dass Windows unter Dateieigenschaften dies für fast alle Dateitypen kann.

    hmm..





  • .. ich glaub COM ist hier der einzigste Weg .. werd was posten wenns klappt







  • Wenn man davon absieht, daß es das einzigste nicht gibt, bist Du auf dem Holzweg. Es gibt natürlich die \005SummaryInformation innerhalb von Compound-Documents. Wenn ich Dich aber richtig verstehe, suchst Du die Informationen, die unter "Dateiinfo" aufgelistet sind. Diese gibt es auch für beispielweise TXT-Files, und das sind nun garantiert keine DOC-Files. Das, was Du da siehst, sind File-Streams. Schau Dir auch das Programm "Streams" an:
    http://www.sysinternals.com/ntw2k/source/misc.shtml#Streams



  • Original erstellt von -King-:
    Wenn man davon absieht, daß es das einzigste nicht gibt, bist Du auf dem Holzweg.

    kannst du mir den satz bitte erklären 😕 kapier ich nicht 😕



  • hat sich erledigt, habs kapiert... 😃



  • Einzig kann man nicht steigern. Oder kann etwas noch einziger als einzig sein? Das Einzigste?

    Oder meintest Du das mit dem Holzweg?

    [edit] Ok, war zu langsam ... [/edit]

    [ Dieser Beitrag wurde am 20.01.2003 um 17:10 Uhr von -King- editiert. ]



  • Also ist teste gerade die einzig* gute Streamvariante.. Man muss sich vorstellen dass ein Editor von einer Datei nur den "::$DATA" - Stream
    zum editieren anzeigt, blos sind alle Infos, wie letze Zugriffszeit in
    anderen Streams versteckt..
    mein Problem ist nun das bei mir nur dieser angezeigt wird.

    Kennt jemand die Funktion

    status = NtQueryInformationFile( fileHandle, &ioStatus,
    streamInfo, streamInfoSize,
    FileStreamInformation )

    .. kann das an "FileStreamInformation" liegen .. bzw. könnte FileAlignementStream funtzen ??.. die MSDN Doku ist echt dürftig hierfür..

    rgs!



  • Sorry, versteh ich nicht. Die Informationen, die Du suchst, liegen im Stream \005SummaryInformation":

    //Der Doppelpunkt hinter dem Dateinamen benennt den Stream
    hStream = CreateFile(TEXT("D:\\test.txt:\005SummaryInformation"), ...);
    

    Das Format scheint das Gleiche zu sein, wie es auch im COM-Stream verwendet wird.

    Woltest Du das wissen?



  • Das war eine sehr sehr gute Info.. den Rest sollte ich selbst schaffen..

    ne main wird gepostet



  • Property Name Property ID String

    Title PID_TITLE 0x00000002 VT_LPSTR

    Subject PID_SUBJECT 0x00000003 VT_LPSTR

    Author PID_AUTHOR 0x00000004 VT_LPSTR

    Keywords PID_KEYWORDS 0x00000005 VT_LPSTR

    Comments PID_COMMENTS 0x00000006 VT_LPSTR
    Kleine VorabInfo: (IDs im SummaryStream)

    Template PID_TEMPLATE 0x00000007 VT_LPSTR

    Last Saved By PID_LASTAUTHOR 0x00000008 VT_LPSTR

    Revision Number PID_REVNUMBER 0x00000009 VT_LPSTR

    Total Editing Time PID_EDITTIME 0x0000000A VT_FILETIME (UTC)

    Last Printed PID_LASTPRINTED 0x0000000B VT_FILETIME (UTC)

    Create Time/Date (*) PID_CREATE_DTM 0x0000000C VT_FILETIME (UTC)

    Last saved Time/Date (*) PID_LASTSAVE_DTM 0x0000000D VT_FILETIME (UTC)



  • Aufruf des ganzen: 
    
    hr=StgOpenStorage ( lpwstr , NULL, STGM_READ | STGM_DIRECT | STGM_PRIORITY,  NULL, 0, &pIStorage );
      GetSummaryInfo ( pIStorage, &Title , &Subject , &Author , &Keywords , &Comments );
    
    //##############################################################
    
    #define UNICODE 1
    #include "afx.h" 
    #include "stdafx.h" 
    #include <afxwin.h>
    #include <windowsx.h> 
    #include <winnls.h> 
    #include <mapinls.h> 
    #include "edk.h" 
    //#include "PostSmpl.h" 
    #include <initguid.h> 
    //#include "freedoc.h" 
    #include "iostream.h" 
    #include <afxres.h>
    
    //LPCSTR _lpa     = NULL;
       int _convert = 0;
    #include <afxconv.h>
    
    LPCSTR _lpa     = NULL;
    
    /* 
     * Data Strcuctures 
     */ 
    
    typedef GUID   FMTID; 
    typedef struct _fmtidoffset 
    { 
       FMTID fmtid;               // FMTID for a section 
       DWORD dwOffset;            // offset of section from start of stream 
    } FMTIDOFFSET; 
    
    typedef struct _propsethdr 
    { 
       WORD  wByteOrder;    // Always 0xFFFE 
       WORD  wFormat;    // Always 0 
       DWORD dwOSVer;    // Hiword: 0=Win16; 1=Mac; 2=Win32 
                         // Loword: GetVersion() 
       CLSID clsid;         // App CLSID 
       DWORD cSections;     // Number of sections 
    } PROPSETHDR; 
    
    typedef DWORD  PID; 
    typedef struct _pidoffset 
    { 
       PID      pid;              // Property ID 
       DWORD dwOffset;            // offset of property from start of section 
    } PIDOFFSET; 
    
    typedef struct _propsectionhdr 
    { 
       DWORD    cbSection;        // Size of this section 
       DWORD    cProps;           // Number of properties in this section 
    } PROPSECTIONHDR; 
    
    /* 
     * Define some of the guids we use 
     */ 
    DEFINE_GUID(FMTID_SumInfo, 0xF29F85E0L, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9); 
    
    typedef struct _mppidmapiprop 
    { 
       WORD     wMapiType;        // MAPI Type 
       LPWSTR      szW;           // MAPI Name 
    } MPPIDMAPIPROP; 
    
    enum pidSumInfo { 
       PID_TITLE = 2, 
       PID_SUBJECT, 
       PID_AUTHOR, 
       PID_KEYWORDS, 
       PID_COMMENTS, 
       cpidSumInfoMax 
    }; 
    
    typedef struct _propsetstminfo 
    { 
       LPOLESTR       szName;              // stream name 
       FMTID const   *pfmtid;              // FMTID of section to promote 
       INT            cmppidmapipropMax;      // Mapping for property names 
       MPPIDMAPIPROP *mppidmapiprop; 
    } PROPSETSTMINFO; 
    
    // Lego workaround - define the symbols for the array 
    
    WCHAR szTitle[]      = L"Title"; 
    WCHAR szSubject[]    = L"Subject"; 
    WCHAR szAuthor[]     = L"Author"; 
    WCHAR szKeywords[]   = L"Keywords"; 
    WCHAR szComments[]   = L"Comments"; 
    
    MPPIDMAPIPROP mppidmapipropSumInfo[] = 
    { 
       {  PT_NULL, NULL        }, // Dictionary 
       {  PT_NULL, NULL        }, // Code page 
       {  PT_STRING8,    szTitle     }, 
       {  PT_STRING8,    szSubject   }, 
       {  PT_STRING8,    szAuthor    }, 
       {  PT_MV_STRING8, szKeywords  }, // Special case VT_LPSTR -> MV 
       {  PT_STRING8,    szComments  } 
    }; 
    
    OLECHAR szSumInfo[] = OLESTR("\005SummaryInformation"); 
    
    PROPSETSTMINFO rgpropsetstminfo[] = 
    { 
       {szSumInfo, &FMTID_SumInfo, cpidSumInfoMax, mppidmapipropSumInfo}, 
       {NULL, NULL, 0, NULL} 
    }; 
    
    // ###################################################################
    
    HRESULT SzDupSz(LPCTSTR sz, LPSTR *lppstr) 
    { 
       INT         cb = 0; 
       HRESULT   hr = NOERROR; 
    
       if (!sz) 
          return hr; 
    
       cb = (lstrlen(sz) + 1) * sizeof(TCHAR); 
       if (!SUCCEEDED(hr = MAPIAllocateBuffer(cb, (LPVOID *)lppstr))) 
             return hr; 
    
       if (!lstrcpy(*lppstr, sz)) 
          return hr; 
    
       return hr; 
    } 
    
    // ##################### PARSE KEYWORD FROM varSTERAM ##############
    
    SCODE ScParseKeywords(LPSPropValue pval, TCHAR * szDefSep) 
    { 
       SCODE    sc= S_OK; 
       LPSTR    szKeywords= pval->Value.lpszA; 
       CHAR *   pch= szKeywords; 
       CHAR *   pchPrev= NULL; 
       LPSTR *  rgsz= NULL; 
       LONG     cKeywords= 0; 
       LONG     isz= 0; 
       TCHAR    szSep[3]; 
       BOOL     fInWord= FALSE; 
       BOOL     fFakeOneWord= FALSE; 
       HRESULT  hr= NOERROR; 
    
       static TCHAR   szScParseKeywords1[] = TEXT("intl"); 
       static TCHAR   szScParseKeywords2[] = TEXT("sList"); 
       static TCHAR   szScParseKeywords3[] = TEXT(","); 
    
       // Get the list separator character 
       GetProfileString(szScParseKeywords1, szScParseKeywords2, 
             szScParseKeywords3, szSep, sizeof(szSep) / sizeof(TCHAR)); 
    
       // Default list separator is the space character 
       if (!szDefSep) 
          szDefSep = TEXT(" "); 
    
       // Loop through the string zero filling non-keywords 
       while (*pch) 
       { 
    #ifdef DBCS 
          if (!FGLeadByte(*pch) && (*pch == szDefSep[0] || *pch == szSep[0])) 
    #else 
          if (*pch == szDefSep[0] || *pch == szSep[0]) 
    #endif 
          { 
             fInWord = FALSE; 
          } 
          else 
          { 
             // If we aren't in a word, we are now 
             if (!fInWord) 
                cKeywords++; 
             fInWord = TRUE; 
          } 
    
          // Remember this position 
          pchPrev = pch; 
    
          // Move forward 
    #ifdef DBCS 
          pch = SzGNext(pch); 
    #else 
          pch = AnsiNext(pch); 
    #endif 
    
          // If we aren't in a word, zap area from our previous position 
          if (!fInWord) 
             ZeroMemory(pchPrev, pch - pchPrev); 
       } 
    
       // Remove leading and trailing spaces from keywords 
    
       pch = szKeywords; 
       isz = cKeywords; 
       while (isz) 
       { 
          isz--; 
    
          // Skip consecutive separators 
          while (!*pch) 
             pch++; 
    
          if (*pch) 
          { 
             // Zero out leading spaces 
             pchPrev = pch; 
             while (isspace(*pch)) 
                pch = AnsiNext(pch); 
             ZeroMemory(pchPrev, pch - pchPrev); 
    
             // Blank keyword 
             if (!*pch) 
             { 
                cKeywords--; 
                continue; 
             } 
    
             // Go to end of string 
             pch = &pch[lstrlen(pch)]; 
    
             // Zero out trailing spaces 
             pchPrev = AnsiPrev(szKeywords, pch); 
             while (isspace(*pchPrev)) 
                pchPrev = AnsiPrev(szKeywords, pchPrev); 
             pchPrev = AnsiNext(pchPrev); 
             ZeroMemory(pchPrev, pch - pchPrev); 
          } 
       } 
    
       // Handle denegerate case where we have no keywords. MAPI requires that 
       // there be a value, though, so we fake up a single empty string 
       if (!cKeywords) 
       { 
          cKeywords = 1; 
          fFakeOneWord = TRUE; 
       } 
    
       // Now that we know how many keywords there are, it's time to allocate 
       // space 
       pval->Value.MVszA.cValues = cKeywords; 
    
       if (!SUCCEEDED(hr = MAPIAllocateBuffer(cKeywords * sizeof(LPSTR), (LPVOID *)&pval->Value.MVszA.lppszA))) 
       { 
           sc = E_OUTOFMEMORY; 
       goto CleanUp; 
       } 
    
       rgsz = pval->Value.MVszA.lppszA; 
    
       if (fFakeOneWord) 
       { 
          if (!SUCCEEDED(hr = SzDupSz((LPSTR) TEXT(""), &rgsz[0]))) 
      sc = E_OUTOFMEMORY; 
          goto CleanUp; 
       } 
    
       // Find the strings we had left over 
       pch = szKeywords; 
       while (isz < cKeywords) 
       { 
       if (*pch) 
       { 
    // Remember the start of the string and then zoom to the end 
       if ( !SUCCEEDED(hr = SzDupSz(pch, &rgsz[isz++]))) 
       { 
       sc = E_OUTOFMEMORY; 
       goto CleanUp; 
       } 
    
       while (*pch) 
    #ifdef DBCS 
                pch = SzGNext(pch); 
    #else 
                ++pch; 
    #endif 
       } 
          ++pch; 
       } 
    
    CleanUp: 
       return sc; 
    } 
    
    //#################### loadstr #####################################
    
    SCODE ScLoadStr(LPSTREAM pstm, CString *lpcstring) 
    { 
       SCODE sc= S_OK; 
       HRESULT  hr= NOERROR; 
       LPSTR lpstr= NULL; 
       DWORD    dwSize= 0; 
    
         // Save string size 
       if (hr = pstm->Read(&dwSize, sizeof(DWORD), NULL)) 
          goto CleanUp; 
    
       // Allocate space for string and then load the string 
       if (dwSize) 
    
    //    hr = MAPIAllocateBuffer(dwSize, (LPVOID *)&lpstr); 
    
          lpstr = (LPSTR)malloc(dwSize);
    
       else 
          hr = SzDupSz((LPTSTR)TEXT(""), &lpstr); 
    
       if (!SUCCEEDED(hr)) 
       { 
          sc = E_OUTOFMEMORY; 
          goto CleanUp; 
       } 
    
       if (dwSize && (hr = pstm->Read(lpstr, dwSize, NULL))) 
       { 
          sc = GetScode(hr); 
          goto CleanUp; 
       } 
    
       *lpcstring = lpstr; 
    
    CleanUp: 
    
       //MAPIFREEBUFFER(lpstr); 
                   free(lpstr); 
    
       return sc; 
    } 
    
    //################## GETSUMMARY INFO ##############################
    
     */ 
    STDAPI GetSummaryInfo 
       ( 
       LPSTORAGE  pstg, 
       CString*  lpsTitle, 
       CString*   lpsSubject, 
       CString*   lpsAuthor, 
       CString*   lpsKeywords, 
       CString*   lpsComments 
       ) 
    { 
       SCODE             sc= S_OK; 
       HRESULT           hr= NOERROR; 
       PROPSETHDR        propsethdr; 
       PROPSECTIONHDR    propsectionhdr; 
       FMTIDOFFSET*      rgfmtidoffset= NULL; 
       FMTIDOFFSET*      pfmtidoffset= NULL; 
       PIDOFFSET*        rgpidoffset= NULL; 
       PIDOFFSET*        ppidoffset= NULL; 
       PROPSETSTMINFO*   ppropsetstminfo = rgpropsetstminfo;    // point to summary info part 
       ULONG             cb= 0; 
       BOOL              fFound= FALSE; 
       BOOL              fSumInfoStm= FALSE; 
       LARGE_INTEGER     li={0}; 
       DWORD             dwType= 0; 
       LPSTREAM          pstm= NULL; 
    
       *lpsTitle   = TEXT(""); 
       *lpsSubject = TEXT(""); 
       *lpsAuthor    = TEXT(""); 
       *lpsKeywords= TEXT(""); 
       *lpsComments= TEXT(""); 
    
       // Open the summay info stream 
       /*sc = pstg->OpenStream(ppropsetstminfo->szName, 
                             NULL, 
                             STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 
                             0, 
                             &pstm); 
       */
       sc = pstg->OpenStream(ppropsetstminfo->szName, 
                             NULL, 
                             STGM_READ  | STGM_SHARE_EXCLUSIVE ,
                             0, 
                             &pstm); 
    
       if (FAILED(sc)) 
          { 
          goto CleanUp; 
          } 
    
       // Read the header to find out how many sections we need to search 
       if (hr = pstm->Read(&propsethdr, sizeof(propsethdr), NULL)) 
          goto ReadError; 
       if (propsethdr.cSections == 0) 
          goto CleanUp; 
    
       // Allocate space for the sections list and read it in 
       cb = propsethdr.cSections * sizeof(FMTIDOFFSET); 
    
       /*
       if (!SUCCEEDED(hr = MAPIAllocateBuffer(cb, (LPVOID *)&rgfmtidoffset))) 
       { 
          sc = E_OUTOFMEMORY; 
      goto CleanUp; 
       } 
       */
    
                      rgfmtidoffset = (FMTIDOFFSET*)malloc(cb);
    
       pfmtidoffset = rgfmtidoffset; 
    
       if (hr = pstm->Read(rgfmtidoffset, cb, NULL)) 
          goto ReadError; 
    
       // Look for the section with the matching FMTID 
       for (fFound = FALSE; propsethdr.cSections--; ++pfmtidoffset) 
       { 
          if (IsEqualGUID(*ppropsetstminfo->pfmtid, pfmtidoffset->fmtid)) 
          { 
             fFound = TRUE; 
             break; 
          } 
       } 
       if (!fFound) 
          goto CleanUp; 
    
       // Are we in the SumInfo stream 
       fSumInfoStm = IsEqualGUID(*ppropsetstminfo->pfmtid, FMTID_SumInfo); 
    
       // Seek to that location in the stream 
       LISet32(li, pfmtidoffset->dwOffset); 
       if (hr = pstm->Seek(li, STREAM_SEEK_SET, NULL)) 
          goto ReadError; 
    
       // Read the section header to find out how many props we need to read 
       if (hr = pstm->Read(&propsectionhdr, sizeof(propsectionhdr), NULL)) 
          goto ReadError; 
       if (propsectionhdr.cProps == 0) 
          goto CleanUp; 
    
       // Allocate space for the props list and read it in 
       cb = propsectionhdr.cProps * sizeof(PIDOFFSET); 
    
       /*       
       if (!SUCCEEDED(hr = MAPIAllocateBuffer(cb, (LPVOID *)&rgpidoffset))) 
       { 
          sc = E_OUTOFMEMORY; 
      goto CleanUp; 
       } 
       */
    
                    rgpidoffset = (PIDOFFSET*)malloc(cb);
       ppidoffset = rgpidoffset; 
    
       if (hr = pstm->Read(rgpidoffset, cb, NULL)) 
          goto ReadError; 
    
       // Go through all the properties 
       for (; propsectionhdr.cProps--; ++ppidoffset) 
       { 
          // Seek to the data 
          LISet32(li, ppidoffset->dwOffset + pfmtidoffset->dwOffset); 
          if (hr = pstm->Seek(li, STREAM_SEEK_SET, NULL)) 
             goto ReadError; 
    
          // Read the type 
          if (hr = pstm->Read(&dwType, sizeof(DWORD), NULL)) 
             goto ReadError; 
    
      // Load the data 
          hr = NOERROR; 
          switch (ppidoffset->pid) 
          { 
          case PID_TITLE: 
             sc = ScLoadStr(pstm, lpsTitle); 
             break; 
    
          case PID_SUBJECT: 
             sc = ScLoadStr(pstm, lpsSubject); 
             break; 
    
          case PID_AUTHOR: 
             sc = ScLoadStr(pstm, lpsAuthor); 
             break; 
    
          case PID_KEYWORDS: 
     sc = ScLoadStr(pstm, lpsKeywords); 
             break; 
    
          case PID_COMMENTS: 
             sc = ScLoadStr(pstm, lpsComments); 
             break; 
    
          default: 
             continue; 
             break; 
          } 
          if (hr) goto ReadError; 
       } 
    
       goto CleanUp; 
    
    ReadError: 
       sc = GetScode(hr); 
    
    CleanUp: 
       free(rgfmtidoffset); 
       free(rgpidoffset); 
       ULRELEASE(pstm); 
       return sc; 
    }
    

    PS. Bitte ändert mein Juniorstatus!)



  • Dein Status hängt soviel ich weiß mit der Anzahl deiner Beiträge zusammen! Also, fleißig schreiben 😉



  • .. warum nicht mit der Größe.. , dann wäre ich doch voll dabei hehe

    naja dan werd ich mal eben mein Senf überall dazugeben

    so ihr lieben .. zeigt euch mal
    🙂 😃 😉 :p 🕶 🙄 😃 🙂


Anmelden zum Antworten