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 WCHAR
*msi_strdupW( const WCHAR
*value
, int len
)
163 if (!value
) return NULL
;
164 if (!(ret
= msi_alloc( (len
+ 1) * sizeof(WCHAR
) ))) return NULL
;
165 memcpy( ret
, value
, len
* sizeof(WCHAR
) );
170 UINT
MSI_RecordCopyField( MSIRECORD
*in_rec
, UINT in_n
,
171 MSIRECORD
*out_rec
, UINT out_n
)
173 UINT r
= ERROR_SUCCESS
;
175 msiobj_lock( &in_rec
->hdr
);
177 if ( in_n
> in_rec
->count
|| out_n
> out_rec
->count
)
178 r
= ERROR_FUNCTION_FAILED
;
179 else if ( in_rec
!= out_rec
|| in_n
!= out_n
)
184 in
= &in_rec
->fields
[in_n
];
185 out
= &out_rec
->fields
[out_n
];
192 out
->u
.iVal
= in
->u
.iVal
;
194 case MSIFIELD_INTPTR
:
195 out
->u
.pVal
= in
->u
.pVal
;
198 if ((str
= msi_strdupW( in
->u
.szwVal
, in
->len
)))
203 else r
= ERROR_OUTOFMEMORY
;
205 case MSIFIELD_STREAM
:
206 IStream_AddRef( in
->u
.stream
);
207 out
->u
.stream
= in
->u
.stream
;
210 ERR("invalid field type %d\n", in
->type
);
212 if (r
== ERROR_SUCCESS
)
213 out
->type
= in
->type
;
216 msiobj_unlock( &in_rec
->hdr
);
220 INT_PTR
MSI_RecordGetIntPtr( MSIRECORD
*rec
, UINT iField
)
224 TRACE( "%p %d\n", rec
, iField
);
226 if( iField
> rec
->count
)
229 switch( rec
->fields
[iField
].type
)
232 return rec
->fields
[iField
].u
.iVal
;
233 case MSIFIELD_INTPTR
:
234 return rec
->fields
[iField
].u
.pVal
;
236 if( string2intW( rec
->fields
[iField
].u
.szwVal
, &ret
) )
246 int MSI_RecordGetInteger( MSIRECORD
*rec
, UINT iField
)
250 TRACE("%p %d\n", rec
, iField
);
252 if( iField
> rec
->count
)
253 return MSI_NULL_INTEGER
;
255 switch( rec
->fields
[iField
].type
)
258 return rec
->fields
[iField
].u
.iVal
;
259 case MSIFIELD_INTPTR
:
260 return rec
->fields
[iField
].u
.pVal
;
262 if( string2intW( rec
->fields
[iField
].u
.szwVal
, &ret
) )
264 return MSI_NULL_INTEGER
;
269 return MSI_NULL_INTEGER
;
272 int WINAPI
MsiRecordGetInteger( MSIHANDLE handle
, UINT iField
)
277 TRACE("%d %d\n", handle
, iField
);
279 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
281 return MSI_NULL_INTEGER
;
283 msiobj_lock( &rec
->hdr
);
284 ret
= MSI_RecordGetInteger( rec
, iField
);
285 msiobj_unlock( &rec
->hdr
);
286 msiobj_release( &rec
->hdr
);
291 UINT WINAPI
MsiRecordClearData( MSIHANDLE handle
)
296 TRACE("%d\n", handle
);
298 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
300 return ERROR_INVALID_HANDLE
;
302 msiobj_lock( &rec
->hdr
);
303 for( i
=0; i
<=rec
->count
; i
++)
305 MSI_FreeField( &rec
->fields
[i
] );
306 rec
->fields
[i
].type
= MSIFIELD_NULL
;
307 rec
->fields
[i
].u
.iVal
= 0;
309 msiobj_unlock( &rec
->hdr
);
310 msiobj_release( &rec
->hdr
);
312 return ERROR_SUCCESS
;
315 UINT
MSI_RecordSetIntPtr( MSIRECORD
*rec
, UINT iField
, INT_PTR pVal
)
317 TRACE("%p %u %ld\n", rec
, iField
, pVal
);
319 if( iField
> rec
->count
)
320 return ERROR_INVALID_PARAMETER
;
322 MSI_FreeField( &rec
->fields
[iField
] );
323 rec
->fields
[iField
].type
= MSIFIELD_INTPTR
;
324 rec
->fields
[iField
].u
.pVal
= pVal
;
326 return ERROR_SUCCESS
;
329 UINT
MSI_RecordSetInteger( MSIRECORD
*rec
, UINT iField
, int iVal
)
331 TRACE("%p %u %d\n", rec
, iField
, iVal
);
333 if( iField
> rec
->count
)
334 return ERROR_INVALID_PARAMETER
;
336 MSI_FreeField( &rec
->fields
[iField
] );
337 rec
->fields
[iField
].type
= MSIFIELD_INT
;
338 rec
->fields
[iField
].u
.iVal
= iVal
;
340 return ERROR_SUCCESS
;
343 UINT WINAPI
MsiRecordSetInteger( MSIHANDLE handle
, UINT iField
, int iVal
)
348 TRACE("%d %u %d\n", handle
, iField
, iVal
);
350 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
352 return ERROR_INVALID_HANDLE
;
354 msiobj_lock( &rec
->hdr
);
355 ret
= MSI_RecordSetInteger( rec
, iField
, iVal
);
356 msiobj_unlock( &rec
->hdr
);
357 msiobj_release( &rec
->hdr
);
361 BOOL
MSI_RecordIsNull( MSIRECORD
*rec
, UINT iField
)
365 TRACE("%p %d\n", rec
, iField
);
367 r
= ( iField
> rec
->count
) ||
368 ( rec
->fields
[iField
].type
== MSIFIELD_NULL
);
373 BOOL WINAPI
MsiRecordIsNull( MSIHANDLE handle
, UINT iField
)
378 TRACE("%d %d\n", handle
, iField
);
380 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
383 msiobj_lock( &rec
->hdr
);
384 ret
= MSI_RecordIsNull( rec
, iField
);
385 msiobj_unlock( &rec
->hdr
);
386 msiobj_release( &rec
->hdr
);
391 UINT
MSI_RecordGetStringA(MSIRECORD
*rec
, UINT iField
,
392 LPSTR szValue
, LPDWORD pcchValue
)
394 UINT len
= 0, ret
= ERROR_SUCCESS
;
397 TRACE("%p %d %p %p\n", rec
, iField
, szValue
, pcchValue
);
399 if( iField
> rec
->count
)
401 if ( szValue
&& *pcchValue
> 0 )
405 return ERROR_SUCCESS
;
408 switch( rec
->fields
[iField
].type
)
411 wsprintfA(buffer
, "%d", rec
->fields
[iField
].u
.iVal
);
412 len
= lstrlenA( buffer
);
414 lstrcpynA(szValue
, buffer
, *pcchValue
);
417 len
= WideCharToMultiByte( CP_ACP
, 0, rec
->fields
[iField
].u
.szwVal
,
418 rec
->fields
[iField
].len
+ 1, NULL
, 0 , NULL
, NULL
);
420 WideCharToMultiByte( CP_ACP
, 0, rec
->fields
[iField
].u
.szwVal
,
421 rec
->fields
[iField
].len
+ 1, szValue
, *pcchValue
, NULL
, NULL
);
422 if( szValue
&& *pcchValue
&& len
>*pcchValue
)
423 szValue
[*pcchValue
-1] = 0;
428 if( szValue
&& *pcchValue
> 0 )
432 ret
= ERROR_INVALID_PARAMETER
;
436 if( szValue
&& *pcchValue
<= len
)
437 ret
= ERROR_MORE_DATA
;
443 UINT WINAPI
MsiRecordGetStringA(MSIHANDLE handle
, UINT iField
,
444 LPSTR szValue
, LPDWORD pcchValue
)
449 TRACE("%d %d %p %p\n", handle
, iField
, szValue
, pcchValue
);
451 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
453 return ERROR_INVALID_HANDLE
;
454 msiobj_lock( &rec
->hdr
);
455 ret
= MSI_RecordGetStringA( rec
, iField
, szValue
, pcchValue
);
456 msiobj_unlock( &rec
->hdr
);
457 msiobj_release( &rec
->hdr
);
461 const WCHAR
*msi_record_get_string( const MSIRECORD
*rec
, UINT field
, int *len
)
463 if (field
> rec
->count
)
466 if (rec
->fields
[field
].type
!= MSIFIELD_WSTR
)
469 if (len
) *len
= rec
->fields
[field
].len
;
471 return rec
->fields
[field
].u
.szwVal
;
474 const WCHAR
*MSI_RecordGetString( const MSIRECORD
*rec
, UINT iField
)
476 return msi_record_get_string( rec
, iField
, NULL
);
479 UINT
MSI_RecordGetStringW(MSIRECORD
*rec
, UINT iField
,
480 LPWSTR szValue
, LPDWORD pcchValue
)
482 static const WCHAR szFormat
[] = {'%','d',0};
483 UINT len
= 0, ret
= ERROR_SUCCESS
;
486 TRACE("%p %d %p %p\n", rec
, iField
, szValue
, pcchValue
);
488 if( iField
> rec
->count
)
490 if ( szValue
&& *pcchValue
> 0 )
494 return ERROR_SUCCESS
;
497 switch( rec
->fields
[iField
].type
)
500 wsprintfW(buffer
, szFormat
, rec
->fields
[iField
].u
.iVal
);
501 len
= lstrlenW( buffer
);
503 lstrcpynW(szValue
, buffer
, *pcchValue
);
506 len
= rec
->fields
[iField
].len
;
508 memcpy( szValue
, rec
->fields
[iField
].u
.szwVal
, min(len
+ 1, *pcchValue
) * sizeof(WCHAR
) );
511 if( szValue
&& *pcchValue
> 0 )
518 if( szValue
&& *pcchValue
<= len
)
519 ret
= ERROR_MORE_DATA
;
525 UINT WINAPI
MsiRecordGetStringW(MSIHANDLE handle
, UINT iField
,
526 LPWSTR szValue
, LPDWORD pcchValue
)
531 TRACE("%d %d %p %p\n", handle
, iField
, szValue
, pcchValue
);
533 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
535 return ERROR_INVALID_HANDLE
;
537 msiobj_lock( &rec
->hdr
);
538 ret
= MSI_RecordGetStringW( rec
, iField
, szValue
, pcchValue
);
539 msiobj_unlock( &rec
->hdr
);
540 msiobj_release( &rec
->hdr
);
544 static UINT
msi_get_stream_size( IStream
*stm
)
549 r
= IStream_Stat( stm
, &stat
, STATFLAG_NONAME
);
552 return stat
.cbSize
.QuadPart
;
555 static UINT
MSI_RecordDataSize(MSIRECORD
*rec
, UINT iField
)
557 TRACE("%p %d\n", rec
, iField
);
559 if( iField
> rec
->count
)
562 switch( rec
->fields
[iField
].type
)
567 return rec
->fields
[iField
].len
;
570 case MSIFIELD_STREAM
:
571 return msi_get_stream_size( rec
->fields
[iField
].u
.stream
);
576 UINT WINAPI
MsiRecordDataSize(MSIHANDLE handle
, UINT iField
)
581 TRACE("%d %d\n", handle
, iField
);
583 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
586 msiobj_lock( &rec
->hdr
);
587 ret
= MSI_RecordDataSize( rec
, iField
);
588 msiobj_unlock( &rec
->hdr
);
589 msiobj_release( &rec
->hdr
);
593 UINT WINAPI
MsiRecordSetStringA( MSIHANDLE handle
, UINT iField
, LPCSTR szValue
)
595 WCHAR
*valueW
= NULL
;
599 TRACE("%d %d %s\n", handle
, iField
, debugstr_a(szValue
));
601 if (szValue
&& !(valueW
= strdupAtoW( szValue
))) return ERROR_OUTOFMEMORY
;
603 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
607 return ERROR_INVALID_HANDLE
;
609 msiobj_lock( &rec
->hdr
);
610 ret
= MSI_RecordSetStringW( rec
, iField
, valueW
);
611 msiobj_unlock( &rec
->hdr
);
612 msiobj_release( &rec
->hdr
);
617 UINT
msi_record_set_string( MSIRECORD
*rec
, UINT field
, const WCHAR
*value
, int len
)
619 if (field
> rec
->count
)
620 return ERROR_INVALID_FIELD
;
622 MSI_FreeField( &rec
->fields
[field
] );
624 if (value
&& len
< 0) len
= strlenW( value
);
628 rec
->fields
[field
].type
= MSIFIELD_WSTR
;
629 rec
->fields
[field
].u
.szwVal
= msi_strdupW( value
, len
);
630 rec
->fields
[field
].len
= len
;
634 rec
->fields
[field
].type
= MSIFIELD_NULL
;
635 rec
->fields
[field
].u
.szwVal
= NULL
;
636 rec
->fields
[field
].len
= 0;
641 UINT
MSI_RecordSetStringW( MSIRECORD
*rec
, UINT iField
, LPCWSTR szValue
)
643 TRACE("%p %d %s\n", rec
, iField
, debugstr_w(szValue
));
645 return msi_record_set_string( rec
, iField
, szValue
, -1 );
648 UINT WINAPI
MsiRecordSetStringW( MSIHANDLE handle
, UINT iField
, LPCWSTR szValue
)
653 TRACE("%d %d %s\n", handle
, iField
, debugstr_w(szValue
));
655 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
657 return ERROR_INVALID_HANDLE
;
659 msiobj_lock( &rec
->hdr
);
660 ret
= MSI_RecordSetStringW( rec
, iField
, szValue
);
661 msiobj_unlock( &rec
->hdr
);
662 msiobj_release( &rec
->hdr
);
666 /* read the data in a file into an IStream */
667 static UINT
RECORD_StreamFromFile(LPCWSTR szFile
, IStream
**pstm
)
669 DWORD sz
, szHighWord
= 0, read
;
673 ULARGE_INTEGER ulSize
;
675 TRACE("reading %s\n", debugstr_w(szFile
));
677 /* read the file into memory */
678 handle
= CreateFileW(szFile
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
679 if( handle
== INVALID_HANDLE_VALUE
)
680 return GetLastError();
681 sz
= GetFileSize(handle
, &szHighWord
);
682 if( sz
!= INVALID_FILE_SIZE
&& szHighWord
== 0 )
684 hGlob
= GlobalAlloc(GMEM_FIXED
, sz
);
687 BOOL r
= ReadFile(handle
, hGlob
, sz
, &read
, NULL
);
697 return ERROR_FUNCTION_FAILED
;
699 /* make a stream out of it, and set the correct file size */
700 hr
= CreateStreamOnHGlobal(hGlob
, TRUE
, pstm
);
704 return ERROR_FUNCTION_FAILED
;
707 /* set the correct size - CreateStreamOnHGlobal screws it up */
708 ulSize
.QuadPart
= sz
;
709 IStream_SetSize(*pstm
, ulSize
);
711 TRACE("read %s, %d bytes into IStream %p\n", debugstr_w(szFile
), sz
, *pstm
);
713 return ERROR_SUCCESS
;
716 UINT
MSI_RecordSetStream(MSIRECORD
*rec
, UINT iField
, IStream
*stream
)
718 if ( (iField
== 0) || (iField
> rec
->count
) )
719 return ERROR_INVALID_PARAMETER
;
721 MSI_FreeField( &rec
->fields
[iField
] );
722 rec
->fields
[iField
].type
= MSIFIELD_STREAM
;
723 rec
->fields
[iField
].u
.stream
= stream
;
725 return ERROR_SUCCESS
;
728 UINT
MSI_RecordSetStreamFromFileW(MSIRECORD
*rec
, UINT iField
, LPCWSTR szFilename
)
733 if( (iField
== 0) || (iField
> rec
->count
) )
734 return ERROR_INVALID_PARAMETER
;
736 /* no filename means we should seek back to the start of the stream */
742 if( rec
->fields
[iField
].type
!= MSIFIELD_STREAM
)
743 return ERROR_INVALID_FIELD
;
745 stm
= rec
->fields
[iField
].u
.stream
;
747 return ERROR_INVALID_FIELD
;
750 r
= IStream_Seek( stm
, ofs
, STREAM_SEEK_SET
, &cur
);
752 return ERROR_FUNCTION_FAILED
;
756 /* read the file into a stream and save the stream in the record */
757 r
= RECORD_StreamFromFile(szFilename
, &stm
);
758 if( r
!= ERROR_SUCCESS
)
761 /* if all's good, store it in the record */
762 MSI_RecordSetStream(rec
, iField
, stm
);
765 return ERROR_SUCCESS
;
768 UINT WINAPI
MsiRecordSetStreamA(MSIHANDLE hRecord
, UINT iField
, LPCSTR szFilename
)
773 TRACE("%d %d %s\n", hRecord
, iField
, debugstr_a(szFilename
));
777 wstr
= strdupAtoW( szFilename
);
779 return ERROR_OUTOFMEMORY
;
781 ret
= MsiRecordSetStreamW(hRecord
, iField
, wstr
);
787 UINT WINAPI
MsiRecordSetStreamW(MSIHANDLE handle
, UINT iField
, LPCWSTR szFilename
)
792 TRACE("%d %d %s\n", handle
, iField
, debugstr_w(szFilename
));
794 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
796 return ERROR_INVALID_HANDLE
;
798 msiobj_lock( &rec
->hdr
);
799 ret
= MSI_RecordSetStreamFromFileW( rec
, iField
, szFilename
);
800 msiobj_unlock( &rec
->hdr
);
801 msiobj_release( &rec
->hdr
);
805 UINT
MSI_RecordReadStream(MSIRECORD
*rec
, UINT iField
, char *buf
, LPDWORD sz
)
811 TRACE("%p %d %p %p\n", rec
, iField
, buf
, sz
);
814 return ERROR_INVALID_PARAMETER
;
816 if( iField
> rec
->count
)
817 return ERROR_INVALID_PARAMETER
;
819 if ( rec
->fields
[iField
].type
== MSIFIELD_NULL
)
822 return ERROR_INVALID_DATA
;
825 if( rec
->fields
[iField
].type
!= MSIFIELD_STREAM
)
826 return ERROR_INVALID_DATATYPE
;
828 stm
= rec
->fields
[iField
].u
.stream
;
830 return ERROR_INVALID_PARAMETER
;
832 /* if there's no buffer pointer, calculate the length to the end */
836 ULARGE_INTEGER end
, cur
;
838 ofs
.QuadPart
= cur
.QuadPart
= 0;
840 IStream_Seek( stm
, ofs
, STREAM_SEEK_SET
, &cur
);
841 IStream_Seek( stm
, ofs
, STREAM_SEEK_END
, &end
);
842 ofs
.QuadPart
= cur
.QuadPart
;
843 IStream_Seek( stm
, ofs
, STREAM_SEEK_SET
, &cur
);
844 *sz
= end
.QuadPart
- cur
.QuadPart
;
846 return ERROR_SUCCESS
;
851 r
= IStream_Read( stm
, buf
, *sz
, &count
);
855 return ERROR_FUNCTION_FAILED
;
860 return ERROR_SUCCESS
;
863 UINT WINAPI
MsiRecordReadStream(MSIHANDLE handle
, UINT iField
, char *buf
, LPDWORD sz
)
868 TRACE("%d %d %p %p\n", handle
, iField
, buf
, sz
);
870 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
872 return ERROR_INVALID_HANDLE
;
873 msiobj_lock( &rec
->hdr
);
874 ret
= MSI_RecordReadStream( rec
, iField
, buf
, sz
);
875 msiobj_unlock( &rec
->hdr
);
876 msiobj_release( &rec
->hdr
);
880 UINT
MSI_RecordSetIStream( MSIRECORD
*rec
, UINT iField
, IStream
*stm
)
882 TRACE("%p %d %p\n", rec
, iField
, stm
);
884 if( iField
> rec
->count
)
885 return ERROR_INVALID_FIELD
;
887 MSI_FreeField( &rec
->fields
[iField
] );
889 rec
->fields
[iField
].type
= MSIFIELD_STREAM
;
890 rec
->fields
[iField
].u
.stream
= stm
;
891 IStream_AddRef( stm
);
893 return ERROR_SUCCESS
;
896 UINT
MSI_RecordGetIStream( MSIRECORD
*rec
, UINT iField
, IStream
**pstm
)
898 TRACE("%p %d %p\n", rec
, iField
, pstm
);
900 if( iField
> rec
->count
)
901 return ERROR_INVALID_FIELD
;
903 if( rec
->fields
[iField
].type
!= MSIFIELD_STREAM
)
904 return ERROR_INVALID_FIELD
;
906 *pstm
= rec
->fields
[iField
].u
.stream
;
907 IStream_AddRef( *pstm
);
909 return ERROR_SUCCESS
;
912 static UINT
msi_dump_stream_to_file( IStream
*stm
, LPCWSTR name
)
920 stgm
= STGM_READWRITE
| STGM_SHARE_EXCLUSIVE
| STGM_FAILIFTHERE
;
921 r
= SHCreateStreamOnFileW( name
, stgm
, &out
);
923 return ERROR_FUNCTION_FAILED
;
926 r
= IStream_Seek( stm
, pos
, STREAM_SEEK_END
, &size
);
931 r
= IStream_Seek( stm
, pos
, STREAM_SEEK_SET
, NULL
);
935 r
= IStream_CopyTo( stm
, out
, size
, NULL
, NULL
);
938 IStream_Release( out
);
940 return ERROR_FUNCTION_FAILED
;
941 return ERROR_SUCCESS
;
944 UINT
MSI_RecordStreamToFile( MSIRECORD
*rec
, UINT iField
, LPCWSTR name
)
949 TRACE("%p %u %s\n", rec
, iField
, debugstr_w(name
));
951 msiobj_lock( &rec
->hdr
);
953 r
= MSI_RecordGetIStream( rec
, iField
, &stm
);
954 if( r
== ERROR_SUCCESS
)
956 r
= msi_dump_stream_to_file( stm
, name
);
957 IStream_Release( stm
);
960 msiobj_unlock( &rec
->hdr
);
965 MSIRECORD
*MSI_CloneRecord(MSIRECORD
*rec
)
970 count
= MSI_RecordGetFieldCount(rec
);
971 clone
= MSI_CreateRecord(count
);
975 for (i
= 0; i
<= count
; i
++)
977 if (rec
->fields
[i
].type
== MSIFIELD_STREAM
)
979 if (FAILED(IStream_Clone(rec
->fields
[i
].u
.stream
,
980 &clone
->fields
[i
].u
.stream
)))
982 msiobj_release(&clone
->hdr
);
985 clone
->fields
[i
].type
= MSIFIELD_STREAM
;
989 r
= MSI_RecordCopyField(rec
, i
, clone
, i
);
990 if (r
!= ERROR_SUCCESS
)
992 msiobj_release(&clone
->hdr
);
1001 BOOL
MSI_RecordsAreFieldsEqual(MSIRECORD
*a
, MSIRECORD
*b
, UINT field
)
1003 if (a
->fields
[field
].type
!= b
->fields
[field
].type
)
1006 switch (a
->fields
[field
].type
)
1012 if (a
->fields
[field
].u
.iVal
!= b
->fields
[field
].u
.iVal
)
1017 if (a
->fields
[field
].len
!= b
->fields
[field
].len
) return FALSE
;
1018 if (memcmp( a
->fields
[field
].u
.szwVal
, b
->fields
[field
].u
.szwVal
,
1019 a
->fields
[field
].len
* sizeof(WCHAR
) )) return FALSE
;
1022 case MSIFIELD_STREAM
:
1030 BOOL
MSI_RecordsAreEqual(MSIRECORD
*a
, MSIRECORD
*b
)
1034 if (a
->count
!= b
->count
)
1037 for (i
= 0; i
<= a
->count
; i
++)
1039 if (!MSI_RecordsAreFieldsEqual( a
, b
, i
))
1046 WCHAR
*msi_dup_record_field( MSIRECORD
*rec
, INT field
)
1052 if (MSI_RecordIsNull( rec
, field
)) return NULL
;
1054 r
= MSI_RecordGetStringW( rec
, field
, NULL
, &sz
);
1055 if (r
!= ERROR_SUCCESS
)
1059 str
= msi_alloc( sz
* sizeof(WCHAR
) );
1060 if (!str
) return NULL
;
1062 r
= MSI_RecordGetStringW( rec
, field
, str
, &sz
);
1063 if (r
!= ERROR_SUCCESS
)
1065 ERR("failed to get string!\n");