Вкладка сведений в окне свойств заполнена обработчиками свойств метаданных .Система свойств метаданных - это то, что Microsoft представила в Windows Vista, и она стала открытой и расширяемой, что позволяет независимым разработчикам (таким как Solidworks) реализовывать и поддерживать свои собственные свойства файлов.Грубо говоря, поток выполнения выглядит примерно так:
User clicks file properties
Look up property handler for the file format
If found property handler:
Query property handler for properties
Populate file details with queried properties
Else:
Populate file details with generic file info
Обработчики свойств являются объектами COM. COM (объектная модель компонентов) - это попытка Microsoft создать независимую от языка объектно-ориентированную инфраструктуру, происхождение которой восходит к девяностым годам, но для целей этого объяснения достаточно сказать, что объект COM являетсякласс C ++, который реализует интерфейс IUnknown
.В дополнение к этому обработчик свойств должен реализовать интерфейс IPropertyStore
:
struct IPropertyStore : public IUnknown
{
public:
virtual HRESULT GetCount(
DWORD *cProps) = 0;
virtual HRESULT GetAt(
DWORD iProp,
PROPERTYKEY *pkey) = 0;
virtual HRESULT GetValue(
REFPROPERTYKEY key,
PROPVARIANT *pv) = 0;
virtual HRESULT SetValue(
REFPROPERTYKEY key,
REFPROPVARIANT propvar) = 0;
virtual HRESULT Commit( void) = 0;
};
Удобная реализация этого интерфейса - CLSID_InMemoryPropertyStore
, предоставленная разработчикам.чтобы облегчить собственную реализацию IPropertyStore
.Интересные методы здесь GetValue
и SetValue
.Для свойств назначается уникальный GUID, который структура PROPERTYKEY
, переданная в эти функции, содержит для идентификации свойства.Детали реализации для GetValue
и SetValue
оставлены на усмотрение разработчика, так что разработчик должен решить, как и где хранить значение для каждого свойства - эти значения могут быть сохранены в другом файле, в потоке альтернативного файла.или в реестре назвать несколько вариантов - но по соображениям транспортабельности рекомендуется хранить значения в самом файле.Таким образом, если файл заархивирован и отправлен, например, по электронной почте, свойства идут вместе с ним.
COM-объект обработчика свойств компилируется в DLL и регистрируется в системе с regsvr32
.Это позволяет Windows знать, где искать свойства для этого конкретного формата файла.После регистрации обработчик свойства можно получить несколькими способами, одним из которых является вспомогательная функция SHGetPropertyStoreFromParsingName
:
HRESULT GetPropertyStore(PCWSTR pszFilename, GETPROPERTYSTOREFLAGS gpsFlags, IPropertyStore** ppps)
{
WCHAR szExpanded[MAX_PATH];
HRESULT hr = ExpandEnvironmentStrings(pszFilename, szExpanded, ARRAYSIZE(szExpanded)) ? S_OK : HRESULT_FROM_WIN32(GetLastError());
if (SUCCEEDED(hr))
{
WCHAR szAbsPath[MAX_PATH];
hr = _wfullpath(szAbsPath, szExpanded, ARRAYSIZE(szAbsPath)) ? S_OK : E_FAIL;
if (SUCCEEDED(hr))
{
hr = SHGetPropertyStoreFromParsingName(szAbsPath, NULL, gpsFlags, IID_PPV_ARGS(ppps));
}
}
return hr;
}
После получения GetValue
и SetValue
можно вызвать для объекта IPropertyStore
, чтобы получить, изменить или установить новое значение для свойства.Однако при использовании SetValue
обязательно вызовите также Commit
.
Microsoft предоставляет утилиту под названием PropertyEdit
, чтобы получитьи установить свойства метаданных для файла как часть их классических образцов Windows.Жаль, что они нигде не упоминают об этом на своих страницах помощи.Поскольку у вас уже установлен Solidworks, обработчик свойств для форматов файлов, которые вас интересуют, уже должен быть зарегистрирован в системе, и это должно быть вопросом компиляции PropertyEdit
и использования его для получения и установки свойств метаданных, поддерживаемых обработчиком.,Это простая утилита командной строки.
Если вам нужно или вы хотите поддерживать собственные метаданные для вашего собственного формата файла, есть также полнофункциональный обработчик свойств образца: RecipePropertyHandler
.
Для справки: установить свойство по его каноническому имени:
HRESULT GetPropertyStore(PCWSTR pszFilename, GETPROPERTYSTOREFLAGS gpsFlags, IPropertyStore** ppps)
{
WCHAR szExpanded[MAX_PATH];
HRESULT hr = ExpandEnvironmentStrings(pszFilename, szExpanded, ARRAYSIZE(szExpanded)) ? S_OK : HRESULT_FROM_WIN32(GetLastError());
if (SUCCEEDED(hr))
{
WCHAR szAbsPath[MAX_PATH];
hr = _wfullpath(szAbsPath, szExpanded, ARRAYSIZE(szAbsPath)) ? S_OK : E_FAIL;
if (SUCCEEDED(hr))
{
hr = SHGetPropertyStoreFromParsingName(szAbsPath, NULL, gpsFlags, IID_PPV_ARGS(ppps));
}
}
return hr;
}
HRESULT SetPropertyValue(PCWSTR pszFilename, PCWSTR pszCanonicalName, PCWSTR pszValue)
{
// Convert the Canonical name of the property to PROPERTYKEY
PROPERTYKEY key;
HRESULT hr = PSGetPropertyKeyFromName(pszCanonicalName, &key);
if (SUCCEEDED(hr))
{
IPropertyStore* pps = NULL;
// Call the helper to get the property store for the
// initialized item
hr = GetPropertyStore(pszFilename, GPS_READWRITE, &pps);
if (SUCCEEDED(hr))
{
PROPVARIANT propvarValue = {0};
hr = InitPropVariantFromString(pszValue, &propvarValue);
if (SUCCEEDED(hr))
{
hr = PSCoerceToCanonicalValue(key, &propvarValue);
if (SUCCEEDED(hr))
{
// Set the value to the property store of the item.
hr = pps->SetValue(key, propvarValue);
if (SUCCEEDED(hr))
{
// Commit does the actual writing back to the file stream.
hr = pps->Commit();
if (SUCCEEDED(hr))
{
wprintf(L"Property %s value %s written successfully \n", pszCanonicalName, pszValue);
}
else
{
wprintf(L"Error %x: Commit to the propertystore failed.\n", hr);
}
}
else
{
wprintf(L"Error %x: Set value to the propertystore failed.\n", hr);
}
}
PropVariantClear(&propvarValue);
}
pps->Release();
}
else
{
wprintf(L"Error %x: getting the propertystore for the item.\n", hr);
}
}
else
{
wprintf(L"Invalid property specified: %s\n", pszCanonicalName);
}
return hr;
}