속성 스토리지 고려 사항
IPropertyStorage::ReadMultiple 은 속성 집합에 있는 것처럼 rgpspec 배열에 지정된 많은 속성을 읽습니다. 요청된 속성을 읽는 한 존재하지 않는 속성을 검색하는 요청은 오류가 아닙니다. 대신 반환 시 해당 속성에 대한 VT_EMPTY rgvar[] 배열에 기록되어야 합니다. 요청된 속성이 없는 경우 메서드는 S_FALSE 반환하고 각 PROPVARIANT에서 VT_EMPTY 설정해야 합니다. 다른 오류가 반환되면 속성 값이 검색되지 않으며 호출자는 오류를 해제하는 것에 대해 걱정할 필요가 없습니다.
rgpspec 매개 변수는 PROPSPEC 구조체의 배열로, 각 속성에 대해 속성 식별자를 지정하거나 속성 식별자가 할당된 경우 문자열 식별자를 지정합니다. IPropertyStorage::WritePropertyNames를 호출하여 문자열을 속성 식별자에 매핑할 수 있습니다. 그러나 속성 식별자의 사용은 문자열 사용보다 훨씬 더 효율적일 수 있습니다.
문자열 이름(PRSPEC_LPWSTR)에 의해 요청되는 속성은 현재 속성 집합(및 현재 시스템 로캘에 따라)에 지정된 속성 식별자(ID)에 대/소문자를 구분하지 않는 방식으로 매핑됩니다.
속성 형식이 VT_LPSTR ANSI 속성 집합에서 속성을 읽는 경우, 즉 속성 집합의 코드 페이지가 유니코드 이외의 값으로 설정되면 속성 값은 속성 집합과 동일한 코드 페이지를 사용합니다. 유니코드 속성 집합에서 VT_LPSTR 속성을 읽을 때 속성 값은 시스템의 현재 기본 ANSI 코드 페이지, 즉 GetACP 함수에서 반환된 코드 페이지를 사용합니다.
스트림 및 스토리지에 대한 포인터인 PROPVARIANT를 제외하고 PROPVARIANT를 간단한 PROPVARIANT라고 합니다. 이러한 간단한 PROPVARIANT는 값별로 데이터를 수신하므로 IPropertyStorage::ReadMultiple 호출은 호출자가 소유한 데이터의 복사본을 제공합니다. 이러한 속성을 만들거나 업데이트하려면 IPropertyStorage::WriteMultiple을 호출합니다.
반면, 변형 형식은 VT_STREAM, VT_STREAMED_OBJECT, VT_STORAGE 및 VT_STORED_OBJECT 단순하지 않은 속성입니다. 이는 값을 제공하는 대신 메서드가 표시된 인터페이스에 대한 포인터를 검색하여 데이터를 읽을 수 있기 때문입니다. 이러한 형식은 단일 속성을 통해 많은 양의 정보를 저장하도록 허용합니다. 비심플 속성을 사용할 때 발생하는 몇 가지 문제가 있습니다.
다른 속성과 마찬가지로 이러한 속성을 만들려면 IPropertyStorage::WriteMultiple을 호출합니다. 그러나 동일한 메서드를 호출하여 업데이트하는 대신 먼저 IPropertyStorage::ReadMultiple 을 호출하여 스트림 또는 스토리지에 대한 인터페이스 포인터를 가져와 서 IStream 또는 IStorage 메서드를 사용하여 데이터를 작성하는 것이 더 효율적입니다. 속성을 통해 열린 스트림 또는 스토리지는 항상 직접 모드로 열리므로 추가 수준의 중첩 트랜잭션이 도입되지 않습니다. 그러나 IPropertySetStorage를 통해 열거나 만든 방법에 따라 속성 집합 전체에 대한 트랜잭션이 여전히 있을 수 있습니다. 또한 속성 집합을 열거나 만들 때 지정된 액세스 및 공유 모드 태그가 속성 기반 스트림 또는 스토리지에 전달됩니다.
속성 기반 스트림 또는 스토리지 포인터의 수명은 이론적으로 연결된 IPropertyStorage 및 IPropertySetStorage 포인터와 독립적이지만 실제로는 사실상 해당 포인터에 따라 달라집니다. 스트림 또는 스토리지를 통해 표시되는 데이터는 포함된 스트림 및 스토리지 하위 개체가 있는 스토리지 개체( IStorage 지원)와 마찬가지로 검색되는 속성 스토리지 개체의 트랜잭션과 관련이 있습니다. 부모 개체의 트랜잭션이 중단되면 해당 개체에 종속된 기존 IStream 및 IStorage 포인터에 더 이상 액세스할 수 없습니다. IPropertyStorage는 속성 스토리지 개체의 유일한 인터페이스이므로 포함된 IStream 및 IStorage 포인터의 유용한 수명은 IPropertyStorage 인터페이스의 수명으로 제한됩니다.
또한 구현은 동일한 IPropertyStorage 인터페이스 instance 통해 동일한 스트림 또는 스토리지 반환 속성이 여러 번 요청되는 상황을 처리해야 합니다. 예를 들어 COM 복합 파일 구현에서 열기는 속성이 이미 열려 있는지 여부에 따라 성공하거나 실패합니다.
또 다른 문제는 트랜잭션 모드에서 여러 열림입니다. 결과는 속성 스토리지가 열렸을 때 IPropertySetStorage 메서드( OPEN 또는Create 메서드를 STGM 플래그를 통해)를 호출하여 지정한 격리 수준에 따라 달라집니다.
속성 집합을 열기 위한 호출이 읽기-쓰기 액세스를 지정하는 경우 IStorage 및 IStream 반환 속성은 항상 읽기-쓰기 액세스 권한으로 열립니다. 그런 다음 이러한 인터페이스를 통해 데이터를 작성하여 속성 값을 변경할 수 있으며, 이는 이러한 속성을 업데이트하는 가장 효율적인 방법입니다. 속성 값 자체에는 추가 수준의 트랜잭션 중첩이 없으므로 속성 스토리지 개체의 트랜잭션(있는 경우)에서 변경 내용의 범위가 지정됩니다.
스토리지 및 스트림 속성
속성 집합에 스트림 또는 스토리지 개체를 쓰려면 속성 집합이 비심플로 만들어졌어야 합니다. 단순 및 비심플 속성 집합에 대한 자세한 내용은 속성 집합에 대한 스토리지 및 스트림 개체 섹션을 참조하세요. rgvar 배열 요소의 vt 필드에 지정된 속성 형식은 스트림 또는 스토리지 유형입니다. VT_STREAM, VT_STORAGE, VT_STREAMED_OBJECT, VT_STORED_OBJECT.
단순하지 않은 속성 집합에서 스트림 또는 스토리지 개체를 속성으로 쓰려면 IPropertyStorage::WriteMultiple을 호출합니다. 이 메서드를 호출하여 단순 속성을 업데이트하지만 속성 집합에서 스트림 및 스토리지 개체를 업데이트하는 효율적인 방법은 아닙니다. WriteMultiple 호출을 통해 이러한 속성 중 하나를 업데이트하면 속성 스토리지 개체에 전달된 데이터의 복사본이 만들어지고 IStorage 또는 IStream 포인터가 이 호출 기간 이후에도 유지되지 않기 때문입니다. 일반적으로 먼저 IPropertyStorage::ReadMultiple 을 호출하여 스트림 또는 스토리지에 대한 인터페이스 포인터를 가져와서 IStream 또는IStorage 메서드를 통해 데이터를 작성하여 스트림 또는 스토리지 개체를 직접 업데이트하는 것이 더 효율적입니다.
예를 들어 IPropertyStorage::WriteMultiple 을 호출하여 NULL 스트림 또는 스토리지 개체를 작성할 수 있습니다. 그런 다음 구현은 속성 집합에 빈 개체를 만듭니다. 그런 다음 IPropertyStorage::ReadMultiple을 호출하여 이 개체에 액세스할 수 있습니다. 이 개체 업데이트를 마치면 업데이트가 속성 집합으로 직접 진행되므로 속성 집합에 쓸 필요가 없습니다.
속성을 통해 열린 스트림 또는 스토리지는 항상 직접 모드로 열리므로 추가 수준의 중첩 트랜잭션이 도입되지 않습니다. 속성 집합 전체에 트랜잭션이 여전히 있을 수 있습니다. 예를 들어 grfmode 매개 변수에 설정된 STGM_TRANSACTED 플래그를 사용하여 IPropertySetStorage::Open을 호출하여 IPropertyStorage를 가져온 경우) 또한 속성 집합의 모드가 지정된 경우 가능한 경우 속성 기반 스트림 또는 스토리지가 읽기-쓰기 모드로 열립니다. 그렇지 않으면 읽기 모드가 사용됩니다.
앞에서 설명한 것처럼 Stream 또는 Storage 개체가 WriteMultiple 메서드를 사용하여 속성 집합에 기록되면 개체의 복사본이 만들어집니다. 스트림 개체에서 이러한 복사본이 만들어지면 원본의 현재 검색 위치에서 복사 작업이 시작됩니다. 검색 위치는 실패 시 정의되지 않지만 성공 시 스트림의 끝에 있습니다. 검색 포인터가 원래 위치로 복원되지 않습니다.
ReadMultiple을 사용하여 속성 집합에서 스트림 또는 스토리지 속성을 읽은 후에도 여전히 열려 있고 동일한 속성에 대한 WriteMultiple에 대한 후속 호출이 수행되면 WriteMultiple 작업이 성공합니다. 이전에 연 스트림 또는 스토리지 속성은 되돌리기 상태로 배치됩니다(이 속성에 대한 모든 호출은 STG_E_REVERTED 오류를 반환합니다).
WriteMultiple 메서드가 속성 배열을 작성할 때 오류를 반환하거나 단순하지 않은 개별 속성을 작성할 때 오류를 반환하는 경우 실제로 작성된 데이터의 양은 정의되지 않습니다.
참조 속성
지정된 PROPVARIANT 구조체에 vt 멤버에 VT_BYREF 플래그가 포함된 경우 연결된 속성은 참조 속성입니다. 참조 속성은 속성 집합에 값을 쓰기 전에 자동으로 역참조됩니다. 예를 들어 PROPVARIANT 구조체의 vt 멤버가 VT_BYREF 형식의 값을 지정하는 경우 | VT_I4 작성된 실제 값은 VT_I4 형식입니다. IPropertyStorage::ReadMultiple 메서드에 대한 후속 호출은 값을 VT_I4 반환합니다. 참조 속성을 사용하는 것은 VariantCopyInd 함수를 호출하는 것과 비슷합니다. VariantCopyInd 는 대상 변형을 해제하고 원본 VARIANTARG의 복사본을 만들어 원본이 VT_BYREF 지정되는 경우 필요한 간접 참조를 수행합니다. 이 함수는 변형의 복사본이 필요할 때 유용하며, 예를 들어 IDispatch::Invoke 구현에서 인수를 처리할 때 VT_BYREF 않도록 보장하는 데 유용합니다.
호출자 참고
IPropertySetStorage::Create의 grfFlags 매개 변수에서 PROPSETFLAG_ANSI 플래그를 설정하지 않고 속성 집합을 유니코드로 만드는 것이 좋습니다. 또한 VT_LPSTR 값을 사용하지 않고 대신 VT_LPWSTR 값을 사용하는 것이 좋습니다. 속성 집합 코드 페이지가 유니코드인 경우 VT_LPSTR 문자열 값은 저장될 때 유니코드로 변환되고 검색될 때 다시 멀티바이트 문자열 값으로 변환됩니다. 속성 집합의 코드 페이지가 유니코드가 아닌 경우 현재 시스템 ANSI 코드 페이지를 사용하여 속성 이름, VT_BSTR 문자열 및 단순하지 않은 속성 값이 저장될 때 멀티바이트 문자열로 변환되고 검색될 때 유니코드로 다시 변환됩니다.
구현자 참고
속성 식별자를 할당할 때 구현은 속성 식별자에 대한 속성 집합에서 현재 사용되지 않는 값을 선택할 수 있습니다( 0 또는 1 또는 0x80000000 초과하지 않는 한 모두 예약된 값임). propidNameFirst 매개 변수는 집합 내의 속성 식별자에 대한 최소값을 설정하며 1보다 크고 0x80000000 미만이어야 합니다. 위의 설명 섹션을 참조하세요.
관련 항목