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
29 #include "wine/debug.h"
30 #include "wine/unicode.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(msidb
);
45 #define MSIFIELD_NULL 0
46 #define MSIFIELD_INT 1
47 #define MSIFIELD_WSTR 3
48 #define MSIFIELD_STREAM 4
49 #define MSIFIELD_INTPTR 5
51 static void MSI_FreeField( MSIFIELD
*field
)
60 msi_free( field
->u
.szwVal
);
63 IStream_Release( field
->u
.stream
);
66 ERR("Invalid field type %d\n", field
->type
);
70 void MSI_CloseRecord( MSIOBJECTHDR
*arg
)
72 MSIRECORD
*rec
= (MSIRECORD
*) arg
;
75 for( i
=0; i
<=rec
->count
; i
++ )
76 MSI_FreeField( &rec
->fields
[i
] );
79 MSIRECORD
*MSI_CreateRecord( UINT cParams
)
84 TRACE("%d\n", cParams
);
89 len
= sizeof (MSIRECORD
) + sizeof (MSIFIELD
)*cParams
;
90 rec
= alloc_msiobject( MSIHANDLETYPE_RECORD
, len
, MSI_CloseRecord
);
96 MSIHANDLE WINAPI
MsiCreateRecord( UINT cParams
)
101 TRACE("%d\n", cParams
);
103 rec
= MSI_CreateRecord( cParams
);
106 ret
= alloc_msihandle( &rec
->hdr
);
107 msiobj_release( &rec
->hdr
);
112 UINT
MSI_RecordGetFieldCount( const MSIRECORD
*rec
)
117 UINT WINAPI
MsiRecordGetFieldCount( MSIHANDLE handle
)
122 TRACE("%d\n", handle
);
124 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
128 msiobj_lock( &rec
->hdr
);
129 ret
= MSI_RecordGetFieldCount( rec
);
130 msiobj_unlock( &rec
->hdr
);
131 msiobj_release( &rec
->hdr
);
136 static BOOL
string2intW( LPCWSTR str
, int *out
)
141 if( *p
== '-' ) /* skip the minus sign */
145 if( (*p
< '0') || (*p
> '9') )
152 if( str
[0] == '-' ) /* check if it's negative */
159 UINT
MSI_RecordCopyField( MSIRECORD
*in_rec
, UINT in_n
,
160 MSIRECORD
*out_rec
, UINT out_n
)
162 UINT r
= ERROR_SUCCESS
;
164 msiobj_lock( &in_rec
->hdr
);
166 if ( in_n
> in_rec
->count
|| out_n
> out_rec
->count
)
167 r
= ERROR_FUNCTION_FAILED
;
168 else if ( in_rec
!= out_rec
|| in_n
!= out_n
)
173 in
= &in_rec
->fields
[in_n
];
174 out
= &out_rec
->fields
[out_n
];
181 out
->u
.iVal
= in
->u
.iVal
;
183 case MSIFIELD_INTPTR
:
184 out
->u
.pVal
= in
->u
.pVal
;
187 str
= strdupW( in
->u
.szwVal
);
189 r
= ERROR_OUTOFMEMORY
;
193 case MSIFIELD_STREAM
:
194 IStream_AddRef( in
->u
.stream
);
195 out
->u
.stream
= in
->u
.stream
;
198 ERR("invalid field type %d\n", in
->type
);
200 if (r
== ERROR_SUCCESS
)
201 out
->type
= in
->type
;
204 msiobj_unlock( &in_rec
->hdr
);
209 INT_PTR
MSI_RecordGetIntPtr( MSIRECORD
*rec
, UINT iField
)
213 TRACE( "%p %d\n", rec
, iField
);
215 if( iField
> rec
->count
)
218 switch( rec
->fields
[iField
].type
)
221 return rec
->fields
[iField
].u
.iVal
;
222 case MSIFIELD_INTPTR
:
223 return rec
->fields
[iField
].u
.pVal
;
225 if( string2intW( rec
->fields
[iField
].u
.szwVal
, &ret
) )
235 int MSI_RecordGetInteger( MSIRECORD
*rec
, UINT iField
)
239 TRACE("%p %d\n", rec
, iField
);
241 if( iField
> rec
->count
)
242 return MSI_NULL_INTEGER
;
244 switch( rec
->fields
[iField
].type
)
247 return rec
->fields
[iField
].u
.iVal
;
248 case MSIFIELD_INTPTR
:
249 return rec
->fields
[iField
].u
.pVal
;
251 if( string2intW( rec
->fields
[iField
].u
.szwVal
, &ret
) )
253 return MSI_NULL_INTEGER
;
258 return MSI_NULL_INTEGER
;
261 int WINAPI
MsiRecordGetInteger( MSIHANDLE handle
, UINT iField
)
266 TRACE("%d %d\n", handle
, iField
);
268 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
270 return MSI_NULL_INTEGER
;
272 msiobj_lock( &rec
->hdr
);
273 ret
= MSI_RecordGetInteger( rec
, iField
);
274 msiobj_unlock( &rec
->hdr
);
275 msiobj_release( &rec
->hdr
);
280 UINT WINAPI
MsiRecordClearData( MSIHANDLE handle
)
285 TRACE("%d\n", handle
);
287 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
289 return ERROR_INVALID_HANDLE
;
291 msiobj_lock( &rec
->hdr
);
292 for( i
=0; i
<=rec
->count
; i
++)
294 MSI_FreeField( &rec
->fields
[i
] );
295 rec
->fields
[i
].type
= MSIFIELD_NULL
;
296 rec
->fields
[i
].u
.iVal
= 0;
298 msiobj_unlock( &rec
->hdr
);
299 msiobj_release( &rec
->hdr
);
301 return ERROR_SUCCESS
;
304 UINT
MSI_RecordSetIntPtr( MSIRECORD
*rec
, UINT iField
, INT_PTR pVal
)
306 TRACE("%p %u %ld\n", rec
, iField
, pVal
);
308 if( iField
> rec
->count
)
309 return ERROR_INVALID_PARAMETER
;
311 MSI_FreeField( &rec
->fields
[iField
] );
312 rec
->fields
[iField
].type
= MSIFIELD_INTPTR
;
313 rec
->fields
[iField
].u
.pVal
= pVal
;
315 return ERROR_SUCCESS
;
318 UINT
MSI_RecordSetInteger( MSIRECORD
*rec
, UINT iField
, int iVal
)
320 TRACE("%p %u %d\n", rec
, iField
, iVal
);
322 if( iField
> rec
->count
)
323 return ERROR_INVALID_PARAMETER
;
325 MSI_FreeField( &rec
->fields
[iField
] );
326 rec
->fields
[iField
].type
= MSIFIELD_INT
;
327 rec
->fields
[iField
].u
.iVal
= iVal
;
329 return ERROR_SUCCESS
;
332 UINT WINAPI
MsiRecordSetInteger( MSIHANDLE handle
, UINT iField
, int iVal
)
337 TRACE("%d %u %d\n", handle
, iField
, iVal
);
339 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
341 return ERROR_INVALID_HANDLE
;
343 msiobj_lock( &rec
->hdr
);
344 ret
= MSI_RecordSetInteger( rec
, iField
, iVal
);
345 msiobj_unlock( &rec
->hdr
);
346 msiobj_release( &rec
->hdr
);
350 BOOL
MSI_RecordIsNull( MSIRECORD
*rec
, UINT iField
)
354 TRACE("%p %d\n", rec
, iField
);
356 r
= ( iField
> rec
->count
) ||
357 ( rec
->fields
[iField
].type
== MSIFIELD_NULL
);
362 BOOL WINAPI
MsiRecordIsNull( MSIHANDLE handle
, UINT iField
)
367 TRACE("%d %d\n", handle
, iField
);
369 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
372 msiobj_lock( &rec
->hdr
);
373 ret
= MSI_RecordIsNull( rec
, iField
);
374 msiobj_unlock( &rec
->hdr
);
375 msiobj_release( &rec
->hdr
);
380 UINT
MSI_RecordGetStringA(MSIRECORD
*rec
, UINT iField
,
381 LPSTR szValue
, LPDWORD pcchValue
)
386 TRACE("%p %d %p %p\n", rec
, iField
, szValue
, pcchValue
);
388 if( iField
> rec
->count
)
390 if ( szValue
&& *pcchValue
> 0 )
394 return ERROR_SUCCESS
;
398 switch( rec
->fields
[iField
].type
)
401 wsprintfA(buffer
, "%d", rec
->fields
[iField
].u
.iVal
);
402 len
= lstrlenA( buffer
);
404 lstrcpynA(szValue
, buffer
, *pcchValue
);
407 len
= WideCharToMultiByte( CP_ACP
, 0, rec
->fields
[iField
].u
.szwVal
, -1,
408 NULL
, 0 , NULL
, NULL
);
410 WideCharToMultiByte( CP_ACP
, 0, rec
->fields
[iField
].u
.szwVal
, -1,
411 szValue
, *pcchValue
, NULL
, NULL
);
412 if( szValue
&& *pcchValue
&& len
>*pcchValue
)
413 szValue
[*pcchValue
-1] = 0;
418 if( szValue
&& *pcchValue
> 0 )
422 ret
= ERROR_INVALID_PARAMETER
;
426 if( szValue
&& *pcchValue
<= len
)
427 ret
= ERROR_MORE_DATA
;
433 UINT WINAPI
MsiRecordGetStringA(MSIHANDLE handle
, UINT iField
,
434 LPSTR szValue
, LPDWORD pcchValue
)
439 TRACE("%d %d %p %p\n", handle
, iField
, szValue
, pcchValue
);
441 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
443 return ERROR_INVALID_HANDLE
;
444 msiobj_lock( &rec
->hdr
);
445 ret
= MSI_RecordGetStringA( rec
, iField
, szValue
, pcchValue
);
446 msiobj_unlock( &rec
->hdr
);
447 msiobj_release( &rec
->hdr
);
451 const WCHAR
*MSI_RecordGetString( const MSIRECORD
*rec
, UINT iField
)
453 if( iField
> rec
->count
)
456 if( rec
->fields
[iField
].type
!= MSIFIELD_WSTR
)
459 return rec
->fields
[iField
].u
.szwVal
;
462 UINT
MSI_RecordGetStringW(MSIRECORD
*rec
, UINT iField
,
463 LPWSTR szValue
, LPDWORD pcchValue
)
467 static const WCHAR szFormat
[] = { '%','d',0 };
469 TRACE("%p %d %p %p\n", rec
, iField
, szValue
, pcchValue
);
471 if( iField
> rec
->count
)
473 if ( szValue
&& *pcchValue
> 0 )
477 return ERROR_SUCCESS
;
481 switch( rec
->fields
[iField
].type
)
484 wsprintfW(buffer
, szFormat
, rec
->fields
[iField
].u
.iVal
);
485 len
= lstrlenW( buffer
);
487 lstrcpynW(szValue
, buffer
, *pcchValue
);
490 len
= lstrlenW( rec
->fields
[iField
].u
.szwVal
);
492 lstrcpynW(szValue
, rec
->fields
[iField
].u
.szwVal
, *pcchValue
);
495 if( szValue
&& *pcchValue
> 0 )
502 if( szValue
&& *pcchValue
<= len
)
503 ret
= ERROR_MORE_DATA
;
509 UINT WINAPI
MsiRecordGetStringW(MSIHANDLE handle
, UINT iField
,
510 LPWSTR szValue
, LPDWORD pcchValue
)
515 TRACE("%d %d %p %p\n", handle
, iField
, szValue
, pcchValue
);
517 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
519 return ERROR_INVALID_HANDLE
;
521 msiobj_lock( &rec
->hdr
);
522 ret
= MSI_RecordGetStringW( rec
, iField
, szValue
, pcchValue
);
523 msiobj_unlock( &rec
->hdr
);
524 msiobj_release( &rec
->hdr
);
528 static UINT
msi_get_stream_size( IStream
*stm
)
533 r
= IStream_Stat( stm
, &stat
, STATFLAG_NONAME
);
536 return stat
.cbSize
.QuadPart
;
539 static UINT
MSI_RecordDataSize(MSIRECORD
*rec
, UINT iField
)
541 TRACE("%p %d\n", rec
, iField
);
543 if( iField
> rec
->count
)
546 switch( rec
->fields
[iField
].type
)
551 return lstrlenW( rec
->fields
[iField
].u
.szwVal
);
554 case MSIFIELD_STREAM
:
555 return msi_get_stream_size( rec
->fields
[iField
].u
.stream
);
560 UINT WINAPI
MsiRecordDataSize(MSIHANDLE handle
, UINT iField
)
565 TRACE("%d %d\n", handle
, iField
);
567 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
570 msiobj_lock( &rec
->hdr
);
571 ret
= MSI_RecordDataSize( rec
, iField
);
572 msiobj_unlock( &rec
->hdr
);
573 msiobj_release( &rec
->hdr
);
577 static UINT
MSI_RecordSetStringA( MSIRECORD
*rec
, UINT iField
, LPCSTR szValue
)
581 TRACE("%p %d %s\n", rec
, iField
, debugstr_a(szValue
));
583 if( iField
> rec
->count
)
584 return ERROR_INVALID_FIELD
;
586 MSI_FreeField( &rec
->fields
[iField
] );
587 if( szValue
&& szValue
[0] )
589 str
= strdupAtoW( szValue
);
590 rec
->fields
[iField
].type
= MSIFIELD_WSTR
;
591 rec
->fields
[iField
].u
.szwVal
= str
;
595 rec
->fields
[iField
].type
= MSIFIELD_NULL
;
596 rec
->fields
[iField
].u
.szwVal
= NULL
;
602 UINT WINAPI
MsiRecordSetStringA( MSIHANDLE handle
, UINT iField
, LPCSTR szValue
)
607 TRACE("%d %d %s\n", handle
, iField
, debugstr_a(szValue
));
609 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
611 return ERROR_INVALID_HANDLE
;
612 msiobj_lock( &rec
->hdr
);
613 ret
= MSI_RecordSetStringA( rec
, iField
, szValue
);
614 msiobj_unlock( &rec
->hdr
);
615 msiobj_release( &rec
->hdr
);
619 UINT
MSI_RecordSetStringW( MSIRECORD
*rec
, UINT iField
, LPCWSTR szValue
)
623 TRACE("%p %d %s\n", rec
, iField
, debugstr_w(szValue
));
625 if( iField
> rec
->count
)
626 return ERROR_INVALID_FIELD
;
628 MSI_FreeField( &rec
->fields
[iField
] );
630 if( szValue
&& szValue
[0] )
632 str
= strdupW( szValue
);
633 rec
->fields
[iField
].type
= MSIFIELD_WSTR
;
634 rec
->fields
[iField
].u
.szwVal
= str
;
638 rec
->fields
[iField
].type
= MSIFIELD_NULL
;
639 rec
->fields
[iField
].u
.szwVal
= NULL
;
645 UINT WINAPI
MsiRecordSetStringW( MSIHANDLE handle
, UINT iField
, LPCWSTR szValue
)
650 TRACE("%d %d %s\n", handle
, iField
, debugstr_w(szValue
));
652 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
654 return ERROR_INVALID_HANDLE
;
656 msiobj_lock( &rec
->hdr
);
657 ret
= MSI_RecordSetStringW( rec
, iField
, szValue
);
658 msiobj_unlock( &rec
->hdr
);
659 msiobj_release( &rec
->hdr
);
663 /* read the data in a file into an IStream */
664 static UINT
RECORD_StreamFromFile(LPCWSTR szFile
, IStream
**pstm
)
666 DWORD sz
, szHighWord
= 0, read
;
670 ULARGE_INTEGER ulSize
;
672 TRACE("reading %s\n", debugstr_w(szFile
));
674 /* read the file into memory */
675 handle
= CreateFileW(szFile
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
676 if( handle
== INVALID_HANDLE_VALUE
)
677 return GetLastError();
678 sz
= GetFileSize(handle
, &szHighWord
);
679 if( sz
!= INVALID_FILE_SIZE
&& szHighWord
== 0 )
681 hGlob
= GlobalAlloc(GMEM_FIXED
, sz
);
684 BOOL r
= ReadFile(handle
, hGlob
, sz
, &read
, NULL
);
694 return ERROR_FUNCTION_FAILED
;
696 /* make a stream out of it, and set the correct file size */
697 hr
= CreateStreamOnHGlobal(hGlob
, TRUE
, pstm
);
701 return ERROR_FUNCTION_FAILED
;
704 /* set the correct size - CreateStreamOnHGlobal screws it up */
705 ulSize
.QuadPart
= sz
;
706 IStream_SetSize(*pstm
, ulSize
);
708 TRACE("read %s, %d bytes into IStream %p\n", debugstr_w(szFile
), sz
, *pstm
);
710 return ERROR_SUCCESS
;
713 UINT
MSI_RecordSetStream(MSIRECORD
*rec
, UINT iField
, IStream
*stream
)
715 if ( (iField
== 0) || (iField
> rec
->count
) )
716 return ERROR_INVALID_PARAMETER
;
718 MSI_FreeField( &rec
->fields
[iField
] );
719 rec
->fields
[iField
].type
= MSIFIELD_STREAM
;
720 rec
->fields
[iField
].u
.stream
= stream
;
722 return ERROR_SUCCESS
;
725 UINT
MSI_RecordSetStreamFromFileW(MSIRECORD
*rec
, UINT iField
, LPCWSTR szFilename
)
730 if( (iField
== 0) || (iField
> rec
->count
) )
731 return ERROR_INVALID_PARAMETER
;
733 /* no filename means we should seek back to the start of the stream */
739 if( rec
->fields
[iField
].type
!= MSIFIELD_STREAM
)
740 return ERROR_INVALID_FIELD
;
742 stm
= rec
->fields
[iField
].u
.stream
;
744 return ERROR_INVALID_FIELD
;
747 r
= IStream_Seek( stm
, ofs
, STREAM_SEEK_SET
, &cur
);
749 return ERROR_FUNCTION_FAILED
;
753 /* read the file into a stream and save the stream in the record */
754 r
= RECORD_StreamFromFile(szFilename
, &stm
);
755 if( r
!= ERROR_SUCCESS
)
758 /* if all's good, store it in the record */
759 MSI_RecordSetStream(rec
, iField
, stm
);
762 return ERROR_SUCCESS
;
765 UINT WINAPI
MsiRecordSetStreamA(MSIHANDLE hRecord
, UINT iField
, LPCSTR szFilename
)
770 TRACE("%d %d %s\n", hRecord
, iField
, debugstr_a(szFilename
));
774 wstr
= strdupAtoW( szFilename
);
776 return ERROR_OUTOFMEMORY
;
778 ret
= MsiRecordSetStreamW(hRecord
, iField
, wstr
);
784 UINT WINAPI
MsiRecordSetStreamW(MSIHANDLE handle
, UINT iField
, LPCWSTR szFilename
)
789 TRACE("%d %d %s\n", handle
, iField
, debugstr_w(szFilename
));
791 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
793 return ERROR_INVALID_HANDLE
;
795 msiobj_lock( &rec
->hdr
);
796 ret
= MSI_RecordSetStreamFromFileW( rec
, iField
, szFilename
);
797 msiobj_unlock( &rec
->hdr
);
798 msiobj_release( &rec
->hdr
);
802 UINT
MSI_RecordReadStream(MSIRECORD
*rec
, UINT iField
, char *buf
, LPDWORD sz
)
808 TRACE("%p %d %p %p\n", rec
, iField
, buf
, sz
);
811 return ERROR_INVALID_PARAMETER
;
813 if( iField
> rec
->count
)
814 return ERROR_INVALID_PARAMETER
;
816 if ( rec
->fields
[iField
].type
== MSIFIELD_NULL
)
819 return ERROR_INVALID_DATA
;
822 if( rec
->fields
[iField
].type
!= MSIFIELD_STREAM
)
823 return ERROR_INVALID_DATATYPE
;
825 stm
= rec
->fields
[iField
].u
.stream
;
827 return ERROR_INVALID_PARAMETER
;
829 /* if there's no buffer pointer, calculate the length to the end */
833 ULARGE_INTEGER end
, cur
;
835 ofs
.QuadPart
= cur
.QuadPart
= 0;
837 IStream_Seek( stm
, ofs
, STREAM_SEEK_SET
, &cur
);
838 IStream_Seek( stm
, ofs
, STREAM_SEEK_END
, &end
);
839 ofs
.QuadPart
= cur
.QuadPart
;
840 IStream_Seek( stm
, ofs
, STREAM_SEEK_SET
, &cur
);
841 *sz
= end
.QuadPart
- cur
.QuadPart
;
843 return ERROR_SUCCESS
;
848 r
= IStream_Read( stm
, buf
, *sz
, &count
);
852 return ERROR_FUNCTION_FAILED
;
857 return ERROR_SUCCESS
;
860 UINT WINAPI
MsiRecordReadStream(MSIHANDLE handle
, UINT iField
, char *buf
, LPDWORD sz
)
865 TRACE("%d %d %p %p\n", handle
, iField
, buf
, sz
);
867 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
869 return ERROR_INVALID_HANDLE
;
870 msiobj_lock( &rec
->hdr
);
871 ret
= MSI_RecordReadStream( rec
, iField
, buf
, sz
);
872 msiobj_unlock( &rec
->hdr
);
873 msiobj_release( &rec
->hdr
);
877 UINT
MSI_RecordSetIStream( MSIRECORD
*rec
, UINT iField
, IStream
*stm
)
879 TRACE("%p %d %p\n", rec
, iField
, stm
);
881 if( iField
> rec
->count
)
882 return ERROR_INVALID_FIELD
;
884 MSI_FreeField( &rec
->fields
[iField
] );
886 rec
->fields
[iField
].type
= MSIFIELD_STREAM
;
887 rec
->fields
[iField
].u
.stream
= stm
;
888 IStream_AddRef( stm
);
890 return ERROR_SUCCESS
;
893 UINT
MSI_RecordGetIStream( MSIRECORD
*rec
, UINT iField
, IStream
**pstm
)
895 TRACE("%p %d %p\n", rec
, iField
, pstm
);
897 if( iField
> rec
->count
)
898 return ERROR_INVALID_FIELD
;
900 if( rec
->fields
[iField
].type
!= MSIFIELD_STREAM
)
901 return ERROR_INVALID_FIELD
;
903 *pstm
= rec
->fields
[iField
].u
.stream
;
904 IStream_AddRef( *pstm
);
906 return ERROR_SUCCESS
;
909 static UINT
msi_dump_stream_to_file( IStream
*stm
, LPCWSTR name
)
917 stgm
= STGM_READWRITE
| STGM_SHARE_EXCLUSIVE
| STGM_FAILIFTHERE
;
918 r
= SHCreateStreamOnFileW( name
, stgm
, &out
);
920 return ERROR_FUNCTION_FAILED
;
923 r
= IStream_Seek( stm
, pos
, STREAM_SEEK_END
, &size
);
928 r
= IStream_Seek( stm
, pos
, STREAM_SEEK_SET
, NULL
);
932 r
= IStream_CopyTo( stm
, out
, size
, NULL
, NULL
);
935 IStream_Release( out
);
937 return ERROR_FUNCTION_FAILED
;
938 return ERROR_SUCCESS
;
941 UINT
MSI_RecordStreamToFile( MSIRECORD
*rec
, UINT iField
, LPCWSTR name
)
946 TRACE("%p %u %s\n", rec
, iField
, debugstr_w(name
));
948 msiobj_lock( &rec
->hdr
);
950 r
= MSI_RecordGetIStream( rec
, iField
, &stm
);
951 if( r
== ERROR_SUCCESS
)
953 r
= msi_dump_stream_to_file( stm
, name
);
954 IStream_Release( stm
);
957 msiobj_unlock( &rec
->hdr
);
962 MSIRECORD
*MSI_CloneRecord(MSIRECORD
*rec
)
967 count
= MSI_RecordGetFieldCount(rec
);
968 clone
= MSI_CreateRecord(count
);
972 for (i
= 0; i
<= count
; i
++)
974 if (rec
->fields
[i
].type
== MSIFIELD_STREAM
)
976 if (FAILED(IStream_Clone(rec
->fields
[i
].u
.stream
,
977 &clone
->fields
[i
].u
.stream
)))
979 msiobj_release(&clone
->hdr
);
982 clone
->fields
[i
].type
= MSIFIELD_STREAM
;
986 r
= MSI_RecordCopyField(rec
, i
, clone
, i
);
987 if (r
!= ERROR_SUCCESS
)
989 msiobj_release(&clone
->hdr
);
998 BOOL
MSI_RecordsAreFieldsEqual(MSIRECORD
*a
, MSIRECORD
*b
, UINT field
)
1000 if (a
->fields
[field
].type
!= b
->fields
[field
].type
)
1003 switch (a
->fields
[field
].type
)
1009 if (a
->fields
[field
].u
.iVal
!= b
->fields
[field
].u
.iVal
)
1014 if (strcmpW(a
->fields
[field
].u
.szwVal
, b
->fields
[field
].u
.szwVal
))
1018 case MSIFIELD_STREAM
:
1026 BOOL
MSI_RecordsAreEqual(MSIRECORD
*a
, MSIRECORD
*b
)
1030 if (a
->count
!= b
->count
)
1033 for (i
= 0; i
<= a
->count
; i
++)
1035 if (!MSI_RecordsAreFieldsEqual( a
, b
, i
))
1042 WCHAR
*msi_dup_record_field( MSIRECORD
*rec
, INT field
)
1048 if (MSI_RecordIsNull( rec
, field
)) return NULL
;
1050 r
= MSI_RecordGetStringW( rec
, field
, NULL
, &sz
);
1051 if (r
!= ERROR_SUCCESS
)
1055 str
= msi_alloc( sz
* sizeof(WCHAR
) );
1056 if (!str
) return NULL
;
1058 r
= MSI_RecordGetStringW( rec
, field
, str
, &sz
);
1059 if (r
!= ERROR_SUCCESS
)
1061 ERR("failed to get string!\n");