2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2002-2004 Mike McCormack for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 WINE_DEFAULT_DEBUG_CHANNEL(msidb
);
25 #define MSIFIELD_NULL 0
26 #define MSIFIELD_INT 1
27 #define MSIFIELD_WSTR 3
28 #define MSIFIELD_STREAM 4
29 #define MSIFIELD_INTPTR 5
31 static void MSI_FreeField( MSIFIELD
*field
)
40 msi_free( field
->u
.szwVal
);
43 IStream_Release( field
->u
.stream
);
46 ERR("Invalid field type %d\n", field
->type
);
50 void MSI_CloseRecord( MSIOBJECTHDR
*arg
)
52 MSIRECORD
*rec
= (MSIRECORD
*) arg
;
55 for( i
=0; i
<=rec
->count
; i
++ )
56 MSI_FreeField( &rec
->fields
[i
] );
59 MSIRECORD
*MSI_CreateRecord( UINT cParams
)
63 TRACE("%d\n", cParams
);
68 rec
= alloc_msiobject( MSIHANDLETYPE_RECORD
, FIELD_OFFSET(MSIRECORD
, fields
[cParams
+ 1]),
75 MSIHANDLE WINAPI
MsiCreateRecord( UINT cParams
)
80 TRACE("%d\n", cParams
);
82 rec
= MSI_CreateRecord( cParams
);
85 ret
= alloc_msihandle( &rec
->hdr
);
86 msiobj_release( &rec
->hdr
);
91 UINT
MSI_RecordGetFieldCount( const MSIRECORD
*rec
)
96 UINT WINAPI
MsiRecordGetFieldCount( MSIHANDLE handle
)
101 TRACE("%d\n", handle
);
103 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
107 msiobj_lock( &rec
->hdr
);
108 ret
= MSI_RecordGetFieldCount( rec
);
109 msiobj_unlock( &rec
->hdr
);
110 msiobj_release( &rec
->hdr
);
115 static BOOL
string2intW( LPCWSTR str
, int *out
)
120 if( *p
== '-' ) /* skip the minus sign */
124 if( (*p
< '0') || (*p
> '9') )
131 if( str
[0] == '-' ) /* check if it's negative */
138 WCHAR
*msi_strdupW( const WCHAR
*value
, int len
)
142 if (!value
) return NULL
;
143 if (!(ret
= msi_alloc( (len
+ 1) * sizeof(WCHAR
) ))) return NULL
;
144 memcpy( ret
, value
, len
* sizeof(WCHAR
) );
149 UINT
MSI_RecordCopyField( MSIRECORD
*in_rec
, UINT in_n
,
150 MSIRECORD
*out_rec
, UINT out_n
)
152 UINT r
= ERROR_SUCCESS
;
154 msiobj_lock( &in_rec
->hdr
);
156 if ( in_n
> in_rec
->count
|| out_n
> out_rec
->count
)
157 r
= ERROR_FUNCTION_FAILED
;
158 else if ( in_rec
!= out_rec
|| in_n
!= out_n
)
163 in
= &in_rec
->fields
[in_n
];
164 out
= &out_rec
->fields
[out_n
];
171 out
->u
.iVal
= in
->u
.iVal
;
173 case MSIFIELD_INTPTR
:
174 out
->u
.pVal
= in
->u
.pVal
;
177 if ((str
= msi_strdupW( in
->u
.szwVal
, in
->len
)))
182 else r
= ERROR_OUTOFMEMORY
;
184 case MSIFIELD_STREAM
:
185 IStream_AddRef( in
->u
.stream
);
186 out
->u
.stream
= in
->u
.stream
;
189 ERR("invalid field type %d\n", in
->type
);
191 if (r
== ERROR_SUCCESS
)
192 out
->type
= in
->type
;
195 msiobj_unlock( &in_rec
->hdr
);
199 INT_PTR
MSI_RecordGetIntPtr( MSIRECORD
*rec
, UINT iField
)
203 TRACE( "%p %d\n", rec
, iField
);
205 if( iField
> rec
->count
)
208 switch( rec
->fields
[iField
].type
)
211 return rec
->fields
[iField
].u
.iVal
;
212 case MSIFIELD_INTPTR
:
213 return rec
->fields
[iField
].u
.pVal
;
215 if( string2intW( rec
->fields
[iField
].u
.szwVal
, &ret
) )
225 int MSI_RecordGetInteger( MSIRECORD
*rec
, UINT iField
)
229 TRACE("%p %d\n", rec
, iField
);
231 if( iField
> rec
->count
)
232 return MSI_NULL_INTEGER
;
234 switch( rec
->fields
[iField
].type
)
237 return rec
->fields
[iField
].u
.iVal
;
238 case MSIFIELD_INTPTR
:
239 return rec
->fields
[iField
].u
.pVal
;
241 if( string2intW( rec
->fields
[iField
].u
.szwVal
, &ret
) )
243 return MSI_NULL_INTEGER
;
248 return MSI_NULL_INTEGER
;
251 int WINAPI
MsiRecordGetInteger( MSIHANDLE handle
, UINT iField
)
256 TRACE("%d %d\n", handle
, iField
);
258 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
260 return MSI_NULL_INTEGER
;
262 msiobj_lock( &rec
->hdr
);
263 ret
= MSI_RecordGetInteger( rec
, iField
);
264 msiobj_unlock( &rec
->hdr
);
265 msiobj_release( &rec
->hdr
);
270 UINT WINAPI
MsiRecordClearData( MSIHANDLE handle
)
275 TRACE("%d\n", handle
);
277 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
279 return ERROR_INVALID_HANDLE
;
281 msiobj_lock( &rec
->hdr
);
282 for( i
=0; i
<=rec
->count
; i
++)
284 MSI_FreeField( &rec
->fields
[i
] );
285 rec
->fields
[i
].type
= MSIFIELD_NULL
;
286 rec
->fields
[i
].u
.iVal
= 0;
288 msiobj_unlock( &rec
->hdr
);
289 msiobj_release( &rec
->hdr
);
291 return ERROR_SUCCESS
;
294 UINT
MSI_RecordSetIntPtr( MSIRECORD
*rec
, UINT iField
, INT_PTR pVal
)
296 TRACE("%p %u %ld\n", rec
, iField
, pVal
);
298 if( iField
> rec
->count
)
299 return ERROR_INVALID_PARAMETER
;
301 MSI_FreeField( &rec
->fields
[iField
] );
302 rec
->fields
[iField
].type
= MSIFIELD_INTPTR
;
303 rec
->fields
[iField
].u
.pVal
= pVal
;
305 return ERROR_SUCCESS
;
308 UINT
MSI_RecordSetInteger( MSIRECORD
*rec
, UINT iField
, int iVal
)
310 TRACE("%p %u %d\n", rec
, iField
, iVal
);
312 if( iField
> rec
->count
)
313 return ERROR_INVALID_PARAMETER
;
315 MSI_FreeField( &rec
->fields
[iField
] );
316 rec
->fields
[iField
].type
= MSIFIELD_INT
;
317 rec
->fields
[iField
].u
.iVal
= iVal
;
319 return ERROR_SUCCESS
;
322 UINT WINAPI
MsiRecordSetInteger( MSIHANDLE handle
, UINT iField
, int iVal
)
327 TRACE("%d %u %d\n", handle
, iField
, iVal
);
329 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
331 return ERROR_INVALID_HANDLE
;
333 msiobj_lock( &rec
->hdr
);
334 ret
= MSI_RecordSetInteger( rec
, iField
, iVal
);
335 msiobj_unlock( &rec
->hdr
);
336 msiobj_release( &rec
->hdr
);
340 BOOL
MSI_RecordIsNull( MSIRECORD
*rec
, UINT iField
)
344 TRACE("%p %d\n", rec
, iField
);
346 r
= ( iField
> rec
->count
) ||
347 ( rec
->fields
[iField
].type
== MSIFIELD_NULL
);
352 BOOL WINAPI
MsiRecordIsNull( MSIHANDLE handle
, UINT iField
)
357 TRACE("%d %d\n", handle
, iField
);
359 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
362 msiobj_lock( &rec
->hdr
);
363 ret
= MSI_RecordIsNull( rec
, iField
);
364 msiobj_unlock( &rec
->hdr
);
365 msiobj_release( &rec
->hdr
);
370 UINT
MSI_RecordGetStringA(MSIRECORD
*rec
, UINT iField
,
371 LPSTR szValue
, LPDWORD pcchValue
)
373 UINT len
= 0, ret
= ERROR_SUCCESS
;
376 TRACE("%p %d %p %p\n", rec
, iField
, szValue
, pcchValue
);
378 if( iField
> rec
->count
)
380 if ( szValue
&& *pcchValue
> 0 )
384 return ERROR_SUCCESS
;
387 switch( rec
->fields
[iField
].type
)
390 wsprintfA(buffer
, "%d", rec
->fields
[iField
].u
.iVal
);
391 len
= lstrlenA( buffer
);
393 lstrcpynA(szValue
, buffer
, *pcchValue
);
396 len
= WideCharToMultiByte( CP_ACP
, 0, rec
->fields
[iField
].u
.szwVal
,
397 rec
->fields
[iField
].len
+ 1, NULL
, 0 , NULL
, NULL
);
399 WideCharToMultiByte( CP_ACP
, 0, rec
->fields
[iField
].u
.szwVal
,
400 rec
->fields
[iField
].len
+ 1, szValue
, *pcchValue
, NULL
, NULL
);
401 if( szValue
&& *pcchValue
&& len
>*pcchValue
)
402 szValue
[*pcchValue
-1] = 0;
407 if( szValue
&& *pcchValue
> 0 )
411 ret
= ERROR_INVALID_PARAMETER
;
415 if( szValue
&& *pcchValue
<= len
)
416 ret
= ERROR_MORE_DATA
;
422 UINT WINAPI
MsiRecordGetStringA(MSIHANDLE handle
, UINT iField
,
423 LPSTR szValue
, LPDWORD pcchValue
)
428 TRACE("%d %d %p %p\n", handle
, iField
, szValue
, pcchValue
);
430 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
432 return ERROR_INVALID_HANDLE
;
433 msiobj_lock( &rec
->hdr
);
434 ret
= MSI_RecordGetStringA( rec
, iField
, szValue
, pcchValue
);
435 msiobj_unlock( &rec
->hdr
);
436 msiobj_release( &rec
->hdr
);
440 const WCHAR
*msi_record_get_string( const MSIRECORD
*rec
, UINT field
, int *len
)
442 if (field
> rec
->count
)
445 if (rec
->fields
[field
].type
!= MSIFIELD_WSTR
)
448 if (len
) *len
= rec
->fields
[field
].len
;
450 return rec
->fields
[field
].u
.szwVal
;
453 const WCHAR
*MSI_RecordGetString( const MSIRECORD
*rec
, UINT iField
)
455 return msi_record_get_string( rec
, iField
, NULL
);
458 UINT
MSI_RecordGetStringW(MSIRECORD
*rec
, UINT iField
,
459 LPWSTR szValue
, LPDWORD pcchValue
)
461 static const WCHAR szFormat
[] = {'%','d',0};
462 UINT len
= 0, ret
= ERROR_SUCCESS
;
465 TRACE("%p %d %p %p\n", rec
, iField
, szValue
, pcchValue
);
467 if( iField
> rec
->count
)
469 if ( szValue
&& *pcchValue
> 0 )
473 return ERROR_SUCCESS
;
476 switch( rec
->fields
[iField
].type
)
479 wsprintfW(buffer
, szFormat
, rec
->fields
[iField
].u
.iVal
);
480 len
= lstrlenW( buffer
);
482 lstrcpynW(szValue
, buffer
, *pcchValue
);
485 len
= rec
->fields
[iField
].len
;
487 memcpy( szValue
, rec
->fields
[iField
].u
.szwVal
, min(len
+ 1, *pcchValue
) * sizeof(WCHAR
) );
490 if( szValue
&& *pcchValue
> 0 )
497 if( szValue
&& *pcchValue
<= len
)
498 ret
= ERROR_MORE_DATA
;
504 UINT WINAPI
MsiRecordGetStringW(MSIHANDLE handle
, UINT iField
,
505 LPWSTR szValue
, LPDWORD pcchValue
)
510 TRACE("%d %d %p %p\n", handle
, iField
, szValue
, pcchValue
);
512 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
514 return ERROR_INVALID_HANDLE
;
516 msiobj_lock( &rec
->hdr
);
517 ret
= MSI_RecordGetStringW( rec
, iField
, szValue
, pcchValue
);
518 msiobj_unlock( &rec
->hdr
);
519 msiobj_release( &rec
->hdr
);
523 static UINT
msi_get_stream_size( IStream
*stm
)
528 r
= IStream_Stat( stm
, &stat
, STATFLAG_NONAME
);
531 return stat
.cbSize
.QuadPart
;
534 static UINT
MSI_RecordDataSize(MSIRECORD
*rec
, UINT iField
)
536 TRACE("%p %d\n", rec
, iField
);
538 if( iField
> rec
->count
)
541 switch( rec
->fields
[iField
].type
)
546 return rec
->fields
[iField
].len
;
549 case MSIFIELD_STREAM
:
550 return msi_get_stream_size( rec
->fields
[iField
].u
.stream
);
555 UINT WINAPI
MsiRecordDataSize(MSIHANDLE handle
, UINT iField
)
560 TRACE("%d %d\n", handle
, iField
);
562 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
565 msiobj_lock( &rec
->hdr
);
566 ret
= MSI_RecordDataSize( rec
, iField
);
567 msiobj_unlock( &rec
->hdr
);
568 msiobj_release( &rec
->hdr
);
572 UINT WINAPI
MsiRecordSetStringA( MSIHANDLE handle
, UINT iField
, LPCSTR szValue
)
574 WCHAR
*valueW
= NULL
;
578 TRACE("%d %d %s\n", handle
, iField
, debugstr_a(szValue
));
580 if (szValue
&& !(valueW
= strdupAtoW( szValue
))) return ERROR_OUTOFMEMORY
;
582 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
586 return ERROR_INVALID_HANDLE
;
588 msiobj_lock( &rec
->hdr
);
589 ret
= MSI_RecordSetStringW( rec
, iField
, valueW
);
590 msiobj_unlock( &rec
->hdr
);
591 msiobj_release( &rec
->hdr
);
596 UINT
msi_record_set_string( MSIRECORD
*rec
, UINT field
, const WCHAR
*value
, int len
)
598 if (field
> rec
->count
)
599 return ERROR_INVALID_FIELD
;
601 MSI_FreeField( &rec
->fields
[field
] );
603 if (value
&& len
< 0) len
= strlenW( value
);
607 rec
->fields
[field
].type
= MSIFIELD_WSTR
;
608 rec
->fields
[field
].u
.szwVal
= msi_strdupW( value
, len
);
609 rec
->fields
[field
].len
= len
;
613 rec
->fields
[field
].type
= MSIFIELD_NULL
;
614 rec
->fields
[field
].u
.szwVal
= NULL
;
615 rec
->fields
[field
].len
= 0;
620 UINT
MSI_RecordSetStringW( MSIRECORD
*rec
, UINT iField
, LPCWSTR szValue
)
622 TRACE("%p %d %s\n", rec
, iField
, debugstr_w(szValue
));
624 return msi_record_set_string( rec
, iField
, szValue
, -1 );
627 UINT WINAPI
MsiRecordSetStringW( MSIHANDLE handle
, UINT iField
, LPCWSTR szValue
)
632 TRACE("%d %d %s\n", handle
, iField
, debugstr_w(szValue
));
634 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
636 return ERROR_INVALID_HANDLE
;
638 msiobj_lock( &rec
->hdr
);
639 ret
= MSI_RecordSetStringW( rec
, iField
, szValue
);
640 msiobj_unlock( &rec
->hdr
);
641 msiobj_release( &rec
->hdr
);
645 /* read the data in a file into an IStream */
646 static UINT
RECORD_StreamFromFile(LPCWSTR szFile
, IStream
**pstm
)
648 DWORD sz
, szHighWord
= 0, read
;
652 ULARGE_INTEGER ulSize
;
654 TRACE("reading %s\n", debugstr_w(szFile
));
656 /* read the file into memory */
657 handle
= CreateFileW(szFile
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
658 if( handle
== INVALID_HANDLE_VALUE
)
659 return GetLastError();
660 sz
= GetFileSize(handle
, &szHighWord
);
661 if( sz
!= INVALID_FILE_SIZE
&& szHighWord
== 0 )
663 hGlob
= GlobalAlloc(GMEM_FIXED
, sz
);
666 BOOL r
= ReadFile(handle
, hGlob
, sz
, &read
, NULL
) && read
== sz
;
676 return ERROR_FUNCTION_FAILED
;
678 /* make a stream out of it, and set the correct file size */
679 hr
= CreateStreamOnHGlobal(hGlob
, TRUE
, pstm
);
683 return ERROR_FUNCTION_FAILED
;
686 /* set the correct size - CreateStreamOnHGlobal screws it up */
687 ulSize
.QuadPart
= sz
;
688 IStream_SetSize(*pstm
, ulSize
);
690 TRACE("read %s, %d bytes into IStream %p\n", debugstr_w(szFile
), sz
, *pstm
);
692 return ERROR_SUCCESS
;
695 UINT
MSI_RecordSetStream(MSIRECORD
*rec
, UINT iField
, IStream
*stream
)
697 if ( (iField
== 0) || (iField
> rec
->count
) )
698 return ERROR_INVALID_PARAMETER
;
700 MSI_FreeField( &rec
->fields
[iField
] );
701 rec
->fields
[iField
].type
= MSIFIELD_STREAM
;
702 rec
->fields
[iField
].u
.stream
= stream
;
704 return ERROR_SUCCESS
;
707 UINT
MSI_RecordSetStreamFromFileW(MSIRECORD
*rec
, UINT iField
, LPCWSTR szFilename
)
712 if( (iField
== 0) || (iField
> rec
->count
) )
713 return ERROR_INVALID_PARAMETER
;
715 /* no filename means we should seek back to the start of the stream */
721 if( rec
->fields
[iField
].type
!= MSIFIELD_STREAM
)
722 return ERROR_INVALID_FIELD
;
724 stm
= rec
->fields
[iField
].u
.stream
;
726 return ERROR_INVALID_FIELD
;
729 r
= IStream_Seek( stm
, ofs
, STREAM_SEEK_SET
, &cur
);
731 return ERROR_FUNCTION_FAILED
;
735 /* read the file into a stream and save the stream in the record */
736 r
= RECORD_StreamFromFile(szFilename
, &stm
);
737 if( r
!= ERROR_SUCCESS
)
740 /* if all's good, store it in the record */
741 MSI_RecordSetStream(rec
, iField
, stm
);
744 return ERROR_SUCCESS
;
747 UINT WINAPI
MsiRecordSetStreamA(MSIHANDLE hRecord
, UINT iField
, LPCSTR szFilename
)
752 TRACE("%d %d %s\n", hRecord
, iField
, debugstr_a(szFilename
));
756 wstr
= strdupAtoW( szFilename
);
758 return ERROR_OUTOFMEMORY
;
760 ret
= MsiRecordSetStreamW(hRecord
, iField
, wstr
);
766 UINT WINAPI
MsiRecordSetStreamW(MSIHANDLE handle
, UINT iField
, LPCWSTR szFilename
)
771 TRACE("%d %d %s\n", handle
, iField
, debugstr_w(szFilename
));
773 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
775 return ERROR_INVALID_HANDLE
;
777 msiobj_lock( &rec
->hdr
);
778 ret
= MSI_RecordSetStreamFromFileW( rec
, iField
, szFilename
);
779 msiobj_unlock( &rec
->hdr
);
780 msiobj_release( &rec
->hdr
);
784 UINT
MSI_RecordReadStream(MSIRECORD
*rec
, UINT iField
, char *buf
, LPDWORD sz
)
790 TRACE("%p %d %p %p\n", rec
, iField
, buf
, sz
);
793 return ERROR_INVALID_PARAMETER
;
795 if( iField
> rec
->count
)
796 return ERROR_INVALID_PARAMETER
;
798 if ( rec
->fields
[iField
].type
== MSIFIELD_NULL
)
801 return ERROR_INVALID_DATA
;
804 if( rec
->fields
[iField
].type
!= MSIFIELD_STREAM
)
805 return ERROR_INVALID_DATATYPE
;
807 stm
= rec
->fields
[iField
].u
.stream
;
809 return ERROR_INVALID_PARAMETER
;
811 /* if there's no buffer pointer, calculate the length to the end */
815 ULARGE_INTEGER end
, cur
;
817 ofs
.QuadPart
= cur
.QuadPart
= 0;
819 IStream_Seek( stm
, ofs
, STREAM_SEEK_SET
, &cur
);
820 IStream_Seek( stm
, ofs
, STREAM_SEEK_END
, &end
);
821 ofs
.QuadPart
= cur
.QuadPart
;
822 IStream_Seek( stm
, ofs
, STREAM_SEEK_SET
, &cur
);
823 *sz
= end
.QuadPart
- cur
.QuadPart
;
825 return ERROR_SUCCESS
;
830 r
= IStream_Read( stm
, buf
, *sz
, &count
);
834 return ERROR_FUNCTION_FAILED
;
839 return ERROR_SUCCESS
;
842 UINT WINAPI
MsiRecordReadStream(MSIHANDLE handle
, UINT iField
, char *buf
, LPDWORD sz
)
847 TRACE("%d %d %p %p\n", handle
, iField
, buf
, sz
);
849 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
851 return ERROR_INVALID_HANDLE
;
852 msiobj_lock( &rec
->hdr
);
853 ret
= MSI_RecordReadStream( rec
, iField
, buf
, sz
);
854 msiobj_unlock( &rec
->hdr
);
855 msiobj_release( &rec
->hdr
);
859 UINT
MSI_RecordSetIStream( MSIRECORD
*rec
, UINT iField
, IStream
*stm
)
861 TRACE("%p %d %p\n", rec
, iField
, stm
);
863 if( iField
> rec
->count
)
864 return ERROR_INVALID_FIELD
;
866 MSI_FreeField( &rec
->fields
[iField
] );
868 rec
->fields
[iField
].type
= MSIFIELD_STREAM
;
869 rec
->fields
[iField
].u
.stream
= stm
;
870 IStream_AddRef( stm
);
872 return ERROR_SUCCESS
;
875 UINT
MSI_RecordGetIStream( MSIRECORD
*rec
, UINT iField
, IStream
**pstm
)
877 TRACE("%p %d %p\n", rec
, iField
, pstm
);
879 if( iField
> rec
->count
)
880 return ERROR_INVALID_FIELD
;
882 if( rec
->fields
[iField
].type
!= MSIFIELD_STREAM
)
883 return ERROR_INVALID_FIELD
;
885 *pstm
= rec
->fields
[iField
].u
.stream
;
886 IStream_AddRef( *pstm
);
888 return ERROR_SUCCESS
;
891 static UINT
msi_dump_stream_to_file( IStream
*stm
, LPCWSTR name
)
899 stgm
= STGM_READWRITE
| STGM_SHARE_EXCLUSIVE
| STGM_FAILIFTHERE
;
900 r
= SHCreateStreamOnFileW( name
, stgm
, &out
);
902 return ERROR_FUNCTION_FAILED
;
905 r
= IStream_Seek( stm
, pos
, STREAM_SEEK_END
, &size
);
910 r
= IStream_Seek( stm
, pos
, STREAM_SEEK_SET
, NULL
);
914 r
= IStream_CopyTo( stm
, out
, size
, NULL
, NULL
);
917 IStream_Release( out
);
919 return ERROR_FUNCTION_FAILED
;
920 return ERROR_SUCCESS
;
923 UINT
MSI_RecordStreamToFile( MSIRECORD
*rec
, UINT iField
, LPCWSTR name
)
928 TRACE("%p %u %s\n", rec
, iField
, debugstr_w(name
));
930 msiobj_lock( &rec
->hdr
);
932 r
= MSI_RecordGetIStream( rec
, iField
, &stm
);
933 if( r
== ERROR_SUCCESS
)
935 r
= msi_dump_stream_to_file( stm
, name
);
936 IStream_Release( stm
);
939 msiobj_unlock( &rec
->hdr
);
944 MSIRECORD
*MSI_CloneRecord(MSIRECORD
*rec
)
949 count
= MSI_RecordGetFieldCount(rec
);
950 clone
= MSI_CreateRecord(count
);
954 for (i
= 0; i
<= count
; i
++)
956 if (rec
->fields
[i
].type
== MSIFIELD_STREAM
)
958 if (FAILED(IStream_Clone(rec
->fields
[i
].u
.stream
,
959 &clone
->fields
[i
].u
.stream
)))
961 msiobj_release(&clone
->hdr
);
964 clone
->fields
[i
].type
= MSIFIELD_STREAM
;
968 r
= MSI_RecordCopyField(rec
, i
, clone
, i
);
969 if (r
!= ERROR_SUCCESS
)
971 msiobj_release(&clone
->hdr
);
980 BOOL
MSI_RecordsAreFieldsEqual(MSIRECORD
*a
, MSIRECORD
*b
, UINT field
)
982 if (a
->fields
[field
].type
!= b
->fields
[field
].type
)
985 switch (a
->fields
[field
].type
)
991 if (a
->fields
[field
].u
.iVal
!= b
->fields
[field
].u
.iVal
)
996 if (a
->fields
[field
].len
!= b
->fields
[field
].len
) return FALSE
;
997 if (memcmp( a
->fields
[field
].u
.szwVal
, b
->fields
[field
].u
.szwVal
,
998 a
->fields
[field
].len
* sizeof(WCHAR
) )) return FALSE
;
1001 case MSIFIELD_STREAM
:
1009 BOOL
MSI_RecordsAreEqual(MSIRECORD
*a
, MSIRECORD
*b
)
1013 if (a
->count
!= b
->count
)
1016 for (i
= 0; i
<= a
->count
; i
++)
1018 if (!MSI_RecordsAreFieldsEqual( a
, b
, i
))
1025 WCHAR
*msi_dup_record_field( MSIRECORD
*rec
, INT field
)
1031 if (MSI_RecordIsNull( rec
, field
)) return NULL
;
1033 r
= MSI_RecordGetStringW( rec
, field
, NULL
, &sz
);
1034 if (r
!= ERROR_SUCCESS
)
1038 str
= msi_alloc( sz
* sizeof(WCHAR
) );
1039 if (!str
) return NULL
;
1041 r
= MSI_RecordGetStringW( rec
, field
, str
, &sz
);
1042 if (r
!= ERROR_SUCCESS
)
1044 ERR("failed to get string!\n");