| OLD | NEW |
| 1 /** | 1 /** |
| 2 * \file property.cpp Implementation of Property class etc. | 2 * \file property.cpp Implementation of Property class etc. |
| 3 */ | 3 */ |
| 4 | 4 |
| 5 #include "installer-lib.h" |
| 5 #include "property.h" | 6 #include "property.h" |
| 6 #include "session.h" | 7 #include "session.h" |
| 7 #include "msiquery.h" | 8 #include <msiquery.h> |
| 8 #include <memory> | 9 #include <memory> |
| 9 | 10 |
| 10 //------------------------------------------------------------------------------
----------- | 11 //------------------------------------------------------------------------------
----------- |
| 11 // Property | 12 // Property |
| 12 //------------------------------------------------------------------------------
----------- | 13 //------------------------------------------------------------------------------
----------- |
| 13 Property::Property( Session & session, std::wstring name ) | 14 Property::Property( Session & session, std::wstring name ) |
| 14 // VSE 2012 shows an IntelliSense error here. Ignore it. The compiler properly
sees the 'friend' declaration. | 15 // VSE 2012 shows an IntelliSense error here. Ignore it. The compiler properly
sees the 'friend' declaration. |
| 15 : handle( session.handle ), name( name ) | 16 : handle( session.handle ), name( name ) |
| 16 {} | 17 {} |
| 17 | 18 |
| 18 /** | 19 /** |
| 19 * \par Implementation | 20 * \par Implementation |
| 20 * The center of the implementation is the <a href="http://msdn.microsoft.com/en
-us/library/windows/desktop/aa370134%28v=vs.85%29.aspx">MsiGetProperty function<
/a>. | 21 * The center of the implementation is the <a href="http://msdn.microsoft.com/en-
us/library/windows/desktop/aa370134%28v=vs.85%29.aspx">MsiGetProperty function</
a>. |
| 21 */ | 22 */ |
| 22 Property::operator std::wstring() const | 23 Property::operator std::wstring() const |
| 23 { | 24 { |
| 24 /* | 25 /* |
| 25 * The screwy logic below arises from how the API works. | 26 * The first call gets the size, but also the actual value if it's short enough
. |
| 26 * MsiGetProperty insists on copying into your buffer, but you don't know how
long that buffer needs to be in advance. | 27 * A second call, if necessary, allocates a sufficiently-long buffer and then g
ets the full value. |
| 27 * The first call gets the size, but also the actual value if it's short enoug
h. | 28 * We use only a modest fixed-size buffer for the first step, because we handle
arbitrary-length property values in a second step. |
| 28 * A second call, if necessary, gets the actual value after allocat | 29 */ |
| 29 */ | 30 // This buffer allocates on the stack, so we don't want it too large; 64 chara
cters is enough for most properties anyway. |
| 30 // We only need a modest fixed-size buffer here, because we handle arbitrary-l
ength property values in a second step. | 31 WCHAR buffer1[ 64 ] = { L'\0' } ; |
| 31 // It has 'auto' allocation, so we don't want it too large. | 32 DWORD length = sizeof( buffer1 ) / sizeof( WCHAR ) ; |
| 32 TCHAR buffer1[ 64 ] = { L'\0' } ; | 33 UINT x = MsiGetPropertyW( handle, name.c_str(), buffer1, & length ) ; |
| 33 DWORD length = sizeof( buffer1 ) / sizeof( TCHAR ) ; | 34 switch ( x ) |
| 34 switch ( MsiGetProperty( handle, name.c_str(), buffer1, & length ) ) | |
| 35 { | 35 { |
| 36 case ERROR_SUCCESS: | 36 case ERROR_SUCCESS: |
| 37 // This call might succeed, which means the return value was short enough to
fit into the buffer. | 37 // This call might succeed, which means the return value was short enough to
fit into the buffer. |
| 38 return std::wstring( buffer1, length ) ; | 38 return std::wstring( buffer1, length ) ; |
| 39 case ERROR_MORE_DATA: | 39 case ERROR_MORE_DATA: |
| 40 // Do nothing yet. | 40 // Do nothing yet. |
| 41 break ; | 41 break ; |
| 42 default: | 42 default: |
| 43 throw std::runtime_error( "Error getting property" ) ; | 43 throw windows_api_error( "MsiGetPropertyW", x, "fixed buffer" ) ; |
| 44 } | 44 } |
| 45 // Assert we received ERROR_MORE_DATA | 45 // Assert we received ERROR_MORE_DATA |
| 46 // unique_ptr handles deallocation transparently | 46 // unique_ptr handles deallocation transparently |
| 47 std::unique_ptr< TCHAR[] > buffer2( new TCHAR[ length ] ); | 47 std::unique_ptr< WCHAR[] > buffer2( new WCHAR[ length ] ) ; |
| 48 switch ( MsiGetProperty( handle, name.c_str(), buffer2.get(), & length ) ) | 48 x = MsiGetPropertyW( handle, name.c_str(), buffer2.get(), & length ) ; |
| 49 switch ( x ) |
| 49 { | 50 { |
| 50 case ERROR_SUCCESS: | 51 case ERROR_SUCCESS: |
| 51 return std::wstring( buffer2.get(), length ) ; | 52 return std::wstring( buffer2.get(), length ) ; |
| 52 default: | 53 default: |
| 53 throw std::runtime_error( "Error getting property" ) ; | 54 throw windows_api_error( "MsiGetPropertyW", x, "allocated buffer" ) ; |
| 54 } | 55 } |
| 55 } | 56 } |
| 56 | 57 |
| 57 /** | 58 /** |
| 58 * \par Implementation | 59 * \par Implementation |
| 59 * The center of the implementation is the <a href="http://msdn.microsoft.com/en
-us/library/windows/desktop/aa370391%28v=vs.85%29.aspx">MsiSetProperty function<
/a>. | 60 * The center of the implementation is the <a href="http://msdn.microsoft.com/en-
us/library/windows/desktop/aa370391%28v=vs.85%29.aspx">MsiSetProperty function</
a>. |
| 60 */ | 61 */ |
| 61 void Property::operator=( const std::wstring & value ) | 62 void Property::operator=( const std::wstring & value ) |
| 62 { | 63 { |
| 63 if ( MsiSetProperty( handle, name.c_str(), value.c_str() ) != ERROR_SUCCESS ) | 64 UINT x = MsiSetPropertyW( handle, name.c_str(), value.c_str() ) ; |
| 65 if ( x != ERROR_SUCCESS ) |
| 64 { | 66 { |
| 65 throw std::runtime_error( "Error setting property" ) ; | 67 throw windows_api_error( "MsiSetPropertyW", x ) ; |
| 66 } | 68 } |
| 67 } | 69 } |
| OLD | NEW |