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
21 #define WIN32_NO_STATUS
23 #define COM_NO_WINDOWS_H
30 //#include "winbase.h"
31 //#include "winuser.h"
32 //#include "winerror.h"
33 #include <wine/debug.h>
34 #include <wine/unicode.h>
36 //#include "msiquery.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(msidb
);
49 #define MSIFIELD_NULL 0
50 #define MSIFIELD_INT 1
51 #define MSIFIELD_WSTR 3
52 #define MSIFIELD_STREAM 4
53 #define MSIFIELD_INTPTR 5
55 static void MSI_FreeField( MSIFIELD
*field
)
64 msi_free( field
->u
.szwVal
);
67 IStream_Release( field
->u
.stream
);
70 ERR("Invalid field type %d\n", field
->type
);
74 void MSI_CloseRecord( MSIOBJECTHDR
*arg
)
76 MSIRECORD
*rec
= (MSIRECORD
*) arg
;
79 for( i
=0; i
<=rec
->count
; i
++ )
80 MSI_FreeField( &rec
->fields
[i
] );
83 MSIRECORD
*MSI_CreateRecord( UINT cParams
)
87 TRACE("%d\n", cParams
);
92 rec
= alloc_msiobject( MSIHANDLETYPE_RECORD
, FIELD_OFFSET(MSIRECORD
, fields
[cParams
+ 1]),
99 MSIHANDLE WINAPI
MsiCreateRecord( UINT cParams
)
104 TRACE("%d\n", cParams
);
106 rec
= MSI_CreateRecord( cParams
);
109 ret
= alloc_msihandle( &rec
->hdr
);
110 msiobj_release( &rec
->hdr
);
115 UINT
MSI_RecordGetFieldCount( const MSIRECORD
*rec
)
120 UINT WINAPI
MsiRecordGetFieldCount( MSIHANDLE handle
)
125 TRACE("%d\n", handle
);
127 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
131 msiobj_lock( &rec
->hdr
);
132 ret
= MSI_RecordGetFieldCount( rec
);
133 msiobj_unlock( &rec
->hdr
);
134 msiobj_release( &rec
->hdr
);
139 static BOOL
string2intW( LPCWSTR str
, int *out
)
144 if( *p
== '-' ) /* skip the minus sign */
148 if( (*p
< '0') || (*p
> '9') )
155 if( str
[0] == '-' ) /* check if it's negative */
162 WCHAR
*msi_strdupW( const WCHAR
*value
, int len
)
166 if (!value
) return NULL
;
167 if (!(ret
= msi_alloc( (len
+ 1) * sizeof(WCHAR
) ))) return NULL
;
168 memcpy( ret
, value
, len
* sizeof(WCHAR
) );
173 UINT
MSI_RecordCopyField( MSIRECORD
*in_rec
, UINT in_n
,
174 MSIRECORD
*out_rec
, UINT out_n
)
176 UINT r
= ERROR_SUCCESS
;
178 msiobj_lock( &in_rec
->hdr
);
180 if ( in_n
> in_rec
->count
|| out_n
> out_rec
->count
)
181 r
= ERROR_FUNCTION_FAILED
;
182 else if ( in_rec
!= out_rec
|| in_n
!= out_n
)
187 in
= &in_rec
->fields
[in_n
];
188 out
= &out_rec
->fields
[out_n
];
195 out
->u
.iVal
= in
->u
.iVal
;
197 case MSIFIELD_INTPTR
:
198 out
->u
.pVal
= in
->u
.pVal
;
201 if ((str
= msi_strdupW( in
->u
.szwVal
, in
->len
)))
206 else r
= ERROR_OUTOFMEMORY
;
208 case MSIFIELD_STREAM
:
209 IStream_AddRef( in
->u
.stream
);
210 out
->u
.stream
= in
->u
.stream
;
213 ERR("invalid field type %d\n", in
->type
);
215 if (r
== ERROR_SUCCESS
)
216 out
->type
= in
->type
;
219 msiobj_unlock( &in_rec
->hdr
);
223 INT_PTR
MSI_RecordGetIntPtr( MSIRECORD
*rec
, UINT iField
)
227 TRACE( "%p %d\n", rec
, iField
);
229 if( iField
> rec
->count
)
232 switch( rec
->fields
[iField
].type
)
235 return rec
->fields
[iField
].u
.iVal
;
236 case MSIFIELD_INTPTR
:
237 return rec
->fields
[iField
].u
.pVal
;
239 if( string2intW( rec
->fields
[iField
].u
.szwVal
, &ret
) )
249 int MSI_RecordGetInteger( MSIRECORD
*rec
, UINT iField
)
253 TRACE("%p %d\n", rec
, iField
);
255 if( iField
> rec
->count
)
256 return MSI_NULL_INTEGER
;
258 switch( rec
->fields
[iField
].type
)
261 return rec
->fields
[iField
].u
.iVal
;
262 case MSIFIELD_INTPTR
:
263 return rec
->fields
[iField
].u
.pVal
;
265 if( string2intW( rec
->fields
[iField
].u
.szwVal
, &ret
) )
267 return MSI_NULL_INTEGER
;
272 return MSI_NULL_INTEGER
;
275 int WINAPI
MsiRecordGetInteger( MSIHANDLE handle
, UINT iField
)
280 TRACE("%d %d\n", handle
, iField
);
282 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
284 return MSI_NULL_INTEGER
;
286 msiobj_lock( &rec
->hdr
);
287 ret
= MSI_RecordGetInteger( rec
, iField
);
288 msiobj_unlock( &rec
->hdr
);
289 msiobj_release( &rec
->hdr
);
294 UINT WINAPI
MsiRecordClearData( MSIHANDLE handle
)
299 TRACE("%d\n", handle
);
301 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
303 return ERROR_INVALID_HANDLE
;
305 msiobj_lock( &rec
->hdr
);
306 for( i
=0; i
<=rec
->count
; i
++)
308 MSI_FreeField( &rec
->fields
[i
] );
309 rec
->fields
[i
].type
= MSIFIELD_NULL
;
310 rec
->fields
[i
].u
.iVal
= 0;
312 msiobj_unlock( &rec
->hdr
);
313 msiobj_release( &rec
->hdr
);
315 return ERROR_SUCCESS
;
318 UINT
MSI_RecordSetIntPtr( MSIRECORD
*rec
, UINT iField
, INT_PTR pVal
)
320 TRACE("%p %u %ld\n", rec
, iField
, pVal
);
322 if( iField
> rec
->count
)
323 return ERROR_INVALID_PARAMETER
;
325 MSI_FreeField( &rec
->fields
[iField
] );
326 rec
->fields
[iField
].type
= MSIFIELD_INTPTR
;
327 rec
->fields
[iField
].u
.pVal
= pVal
;
329 return ERROR_SUCCESS
;
332 UINT
MSI_RecordSetInteger( MSIRECORD
*rec
, UINT iField
, int iVal
)
334 TRACE("%p %u %d\n", rec
, iField
, iVal
);
336 if( iField
> rec
->count
)
337 return ERROR_INVALID_PARAMETER
;
339 MSI_FreeField( &rec
->fields
[iField
] );
340 rec
->fields
[iField
].type
= MSIFIELD_INT
;
341 rec
->fields
[iField
].u
.iVal
= iVal
;
343 return ERROR_SUCCESS
;
346 UINT WINAPI
MsiRecordSetInteger( MSIHANDLE handle
, UINT iField
, int iVal
)
351 TRACE("%d %u %d\n", handle
, iField
, iVal
);
353 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
355 return ERROR_INVALID_HANDLE
;
357 msiobj_lock( &rec
->hdr
);
358 ret
= MSI_RecordSetInteger( rec
, iField
, iVal
);
359 msiobj_unlock( &rec
->hdr
);
360 msiobj_release( &rec
->hdr
);
364 BOOL
MSI_RecordIsNull( MSIRECORD
*rec
, UINT iField
)
368 TRACE("%p %d\n", rec
, iField
);
370 r
= ( iField
> rec
->count
) ||
371 ( rec
->fields
[iField
].type
== MSIFIELD_NULL
);
376 BOOL WINAPI
MsiRecordIsNull( MSIHANDLE handle
, UINT iField
)
381 TRACE("%d %d\n", handle
, iField
);
383 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
386 msiobj_lock( &rec
->hdr
);
387 ret
= MSI_RecordIsNull( rec
, iField
);
388 msiobj_unlock( &rec
->hdr
);
389 msiobj_release( &rec
->hdr
);
394 UINT
MSI_RecordGetStringA(MSIRECORD
*rec
, UINT iField
,
395 LPSTR szValue
, LPDWORD pcchValue
)
397 UINT len
= 0, ret
= ERROR_SUCCESS
;
400 TRACE("%p %d %p %p\n", rec
, iField
, szValue
, pcchValue
);
402 if( iField
> rec
->count
)
404 if ( szValue
&& *pcchValue
> 0 )
408 return ERROR_SUCCESS
;
411 switch( rec
->fields
[iField
].type
)
414 wsprintfA(buffer
, "%d", rec
->fields
[iField
].u
.iVal
);
415 len
= lstrlenA( buffer
);
417 lstrcpynA(szValue
, buffer
, *pcchValue
);
420 len
= WideCharToMultiByte( CP_ACP
, 0, rec
->fields
[iField
].u
.szwVal
,
421 rec
->fields
[iField
].len
+ 1, NULL
, 0 , NULL
, NULL
);
423 WideCharToMultiByte( CP_ACP
, 0, rec
->fields
[iField
].u
.szwVal
,
424 rec
->fields
[iField
].len
+ 1, szValue
, *pcchValue
, NULL
, NULL
);
425 if( szValue
&& *pcchValue
&& len
>*pcchValue
)
426 szValue
[*pcchValue
-1] = 0;
431 if( szValue
&& *pcchValue
> 0 )
435 ret
= ERROR_INVALID_PARAMETER
;
439 if( szValue
&& *pcchValue
<= len
)
440 ret
= ERROR_MORE_DATA
;
446 UINT WINAPI
MsiRecordGetStringA(MSIHANDLE handle
, UINT iField
,
447 LPSTR szValue
, LPDWORD pcchValue
)
452 TRACE("%d %d %p %p\n", handle
, iField
, szValue
, pcchValue
);
454 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
456 return ERROR_INVALID_HANDLE
;
457 msiobj_lock( &rec
->hdr
);
458 ret
= MSI_RecordGetStringA( rec
, iField
, szValue
, pcchValue
);
459 msiobj_unlock( &rec
->hdr
);
460 msiobj_release( &rec
->hdr
);
464 const WCHAR
*msi_record_get_string( const MSIRECORD
*rec
, UINT field
, int *len
)
466 if (field
> rec
->count
)
469 if (rec
->fields
[field
].type
!= MSIFIELD_WSTR
)
472 if (len
) *len
= rec
->fields
[field
].len
;
474 return rec
->fields
[field
].u
.szwVal
;
477 const WCHAR
*MSI_RecordGetString( const MSIRECORD
*rec
, UINT iField
)
479 return msi_record_get_string( rec
, iField
, NULL
);
482 UINT
MSI_RecordGetStringW(MSIRECORD
*rec
, UINT iField
,
483 LPWSTR szValue
, LPDWORD pcchValue
)
485 static const WCHAR szFormat
[] = {'%','d',0};
486 UINT len
= 0, ret
= ERROR_SUCCESS
;
489 TRACE("%p %d %p %p\n", rec
, iField
, szValue
, pcchValue
);
491 if( iField
> rec
->count
)
493 if ( szValue
&& *pcchValue
> 0 )
497 return ERROR_SUCCESS
;
500 switch( rec
->fields
[iField
].type
)
503 wsprintfW(buffer
, szFormat
, rec
->fields
[iField
].u
.iVal
);
504 len
= lstrlenW( buffer
);
506 lstrcpynW(szValue
, buffer
, *pcchValue
);
509 len
= rec
->fields
[iField
].len
;
511 memcpy( szValue
, rec
->fields
[iField
].u
.szwVal
, min(len
+ 1, *pcchValue
) * sizeof(WCHAR
) );
514 if( szValue
&& *pcchValue
> 0 )
521 if( szValue
&& *pcchValue
<= len
)
522 ret
= ERROR_MORE_DATA
;
528 UINT WINAPI
MsiRecordGetStringW(MSIHANDLE handle
, UINT iField
,
529 LPWSTR szValue
, LPDWORD pcchValue
)
534 TRACE("%d %d %p %p\n", handle
, iField
, szValue
, pcchValue
);
536 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
538 return ERROR_INVALID_HANDLE
;
540 msiobj_lock( &rec
->hdr
);
541 ret
= MSI_RecordGetStringW( rec
, iField
, szValue
, pcchValue
);
542 msiobj_unlock( &rec
->hdr
);
543 msiobj_release( &rec
->hdr
);
547 static UINT
msi_get_stream_size( IStream
*stm
)
552 r
= IStream_Stat( stm
, &stat
, STATFLAG_NONAME
);
555 return stat
.cbSize
.QuadPart
;
558 static UINT
MSI_RecordDataSize(MSIRECORD
*rec
, UINT iField
)
560 TRACE("%p %d\n", rec
, iField
);
562 if( iField
> rec
->count
)
565 switch( rec
->fields
[iField
].type
)
570 return rec
->fields
[iField
].len
;
573 case MSIFIELD_STREAM
:
574 return msi_get_stream_size( rec
->fields
[iField
].u
.stream
);
579 UINT WINAPI
MsiRecordDataSize(MSIHANDLE handle
, UINT iField
)
584 TRACE("%d %d\n", handle
, iField
);
586 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
589 msiobj_lock( &rec
->hdr
);
590 ret
= MSI_RecordDataSize( rec
, iField
);
591 msiobj_unlock( &rec
->hdr
);
592 msiobj_release( &rec
->hdr
);
596 UINT WINAPI
MsiRecordSetStringA( MSIHANDLE handle
, UINT iField
, LPCSTR szValue
)
598 WCHAR
*valueW
= NULL
;
602 TRACE("%d %d %s\n", handle
, iField
, debugstr_a(szValue
));
604 if (szValue
&& !(valueW
= strdupAtoW( szValue
))) return ERROR_OUTOFMEMORY
;
606 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
610 return ERROR_INVALID_HANDLE
;
612 msiobj_lock( &rec
->hdr
);
613 ret
= MSI_RecordSetStringW( rec
, iField
, valueW
);
614 msiobj_unlock( &rec
->hdr
);
615 msiobj_release( &rec
->hdr
);
620 UINT
msi_record_set_string( MSIRECORD
*rec
, UINT field
, const WCHAR
*value
, int len
)
622 if (field
> rec
->count
)
623 return ERROR_INVALID_FIELD
;
625 MSI_FreeField( &rec
->fields
[field
] );
627 if (value
&& len
< 0) len
= strlenW( value
);
631 rec
->fields
[field
].type
= MSIFIELD_WSTR
;
632 rec
->fields
[field
].u
.szwVal
= msi_strdupW( value
, len
);
633 rec
->fields
[field
].len
= len
;
637 rec
->fields
[field
].type
= MSIFIELD_NULL
;
638 rec
->fields
[field
].u
.szwVal
= NULL
;
639 rec
->fields
[field
].len
= 0;
644 UINT
MSI_RecordSetStringW( MSIRECORD
*rec
, UINT iField
, LPCWSTR szValue
)
646 TRACE("%p %d %s\n", rec
, iField
, debugstr_w(szValue
));
648 return msi_record_set_string( rec
, iField
, szValue
, -1 );
651 UINT WINAPI
MsiRecordSetStringW( MSIHANDLE handle
, UINT iField
, LPCWSTR szValue
)
656 TRACE("%d %d %s\n", handle
, iField
, debugstr_w(szValue
));
658 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
660 return ERROR_INVALID_HANDLE
;
662 msiobj_lock( &rec
->hdr
);
663 ret
= MSI_RecordSetStringW( rec
, iField
, szValue
);
664 msiobj_unlock( &rec
->hdr
);
665 msiobj_release( &rec
->hdr
);
669 /* read the data in a file into an IStream */
670 static UINT
RECORD_StreamFromFile(LPCWSTR szFile
, IStream
**pstm
)
672 DWORD sz
, szHighWord
= 0, read
;
676 ULARGE_INTEGER ulSize
;
678 TRACE("reading %s\n", debugstr_w(szFile
));
680 /* read the file into memory */
681 handle
= CreateFileW(szFile
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
682 if( handle
== INVALID_HANDLE_VALUE
)
683 return GetLastError();
684 sz
= GetFileSize(handle
, &szHighWord
);
685 if( sz
!= INVALID_FILE_SIZE
&& szHighWord
== 0 )
687 hGlob
= GlobalAlloc(GMEM_FIXED
, sz
);
690 BOOL r
= ReadFile(handle
, hGlob
, sz
, &read
, NULL
);
700 return ERROR_FUNCTION_FAILED
;
702 /* make a stream out of it, and set the correct file size */
703 hr
= CreateStreamOnHGlobal(hGlob
, TRUE
, pstm
);
707 return ERROR_FUNCTION_FAILED
;
710 /* set the correct size - CreateStreamOnHGlobal screws it up */
711 ulSize
.QuadPart
= sz
;
712 IStream_SetSize(*pstm
, ulSize
);
714 TRACE("read %s, %d bytes into IStream %p\n", debugstr_w(szFile
), sz
, *pstm
);
716 return ERROR_SUCCESS
;
719 UINT
MSI_RecordSetStream(MSIRECORD
*rec
, UINT iField
, IStream
*stream
)
721 if ( (iField
== 0) || (iField
> rec
->count
) )
722 return ERROR_INVALID_PARAMETER
;
724 MSI_FreeField( &rec
->fields
[iField
] );
725 rec
->fields
[iField
].type
= MSIFIELD_STREAM
;
726 rec
->fields
[iField
].u
.stream
= stream
;
728 return ERROR_SUCCESS
;
731 UINT
MSI_RecordSetStreamFromFileW(MSIRECORD
*rec
, UINT iField
, LPCWSTR szFilename
)
736 if( (iField
== 0) || (iField
> rec
->count
) )
737 return ERROR_INVALID_PARAMETER
;
739 /* no filename means we should seek back to the start of the stream */
745 if( rec
->fields
[iField
].type
!= MSIFIELD_STREAM
)
746 return ERROR_INVALID_FIELD
;
748 stm
= rec
->fields
[iField
].u
.stream
;
750 return ERROR_INVALID_FIELD
;
753 r
= IStream_Seek( stm
, ofs
, STREAM_SEEK_SET
, &cur
);
755 return ERROR_FUNCTION_FAILED
;
759 /* read the file into a stream and save the stream in the record */
760 r
= RECORD_StreamFromFile(szFilename
, &stm
);
761 if( r
!= ERROR_SUCCESS
)
764 /* if all's good, store it in the record */
765 MSI_RecordSetStream(rec
, iField
, stm
);
768 return ERROR_SUCCESS
;
771 UINT WINAPI
MsiRecordSetStreamA(MSIHANDLE hRecord
, UINT iField
, LPCSTR szFilename
)
776 TRACE("%d %d %s\n", hRecord
, iField
, debugstr_a(szFilename
));
780 wstr
= strdupAtoW( szFilename
);
782 return ERROR_OUTOFMEMORY
;
784 ret
= MsiRecordSetStreamW(hRecord
, iField
, wstr
);
790 UINT WINAPI
MsiRecordSetStreamW(MSIHANDLE handle
, UINT iField
, LPCWSTR szFilename
)
795 TRACE("%d %d %s\n", handle
, iField
, debugstr_w(szFilename
));
797 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
799 return ERROR_INVALID_HANDLE
;
801 msiobj_lock( &rec
->hdr
);
802 ret
= MSI_RecordSetStreamFromFileW( rec
, iField
, szFilename
);
803 msiobj_unlock( &rec
->hdr
);
804 msiobj_release( &rec
->hdr
);
808 UINT
MSI_RecordReadStream(MSIRECORD
*rec
, UINT iField
, char *buf
, LPDWORD sz
)
814 TRACE("%p %d %p %p\n", rec
, iField
, buf
, sz
);
817 return ERROR_INVALID_PARAMETER
;
819 if( iField
> rec
->count
)
820 return ERROR_INVALID_PARAMETER
;
822 if ( rec
->fields
[iField
].type
== MSIFIELD_NULL
)
825 return ERROR_INVALID_DATA
;
828 if( rec
->fields
[iField
].type
!= MSIFIELD_STREAM
)
829 return ERROR_INVALID_DATATYPE
;
831 stm
= rec
->fields
[iField
].u
.stream
;
833 return ERROR_INVALID_PARAMETER
;
835 /* if there's no buffer pointer, calculate the length to the end */
839 ULARGE_INTEGER end
, cur
;
841 ofs
.QuadPart
= cur
.QuadPart
= 0;
843 IStream_Seek( stm
, ofs
, STREAM_SEEK_SET
, &cur
);
844 IStream_Seek( stm
, ofs
, STREAM_SEEK_END
, &end
);
845 ofs
.QuadPart
= cur
.QuadPart
;
846 IStream_Seek( stm
, ofs
, STREAM_SEEK_SET
, &cur
);
847 *sz
= end
.QuadPart
- cur
.QuadPart
;
849 return ERROR_SUCCESS
;
854 r
= IStream_Read( stm
, buf
, *sz
, &count
);
858 return ERROR_FUNCTION_FAILED
;
863 return ERROR_SUCCESS
;
866 UINT WINAPI
MsiRecordReadStream(MSIHANDLE handle
, UINT iField
, char *buf
, LPDWORD sz
)
871 TRACE("%d %d %p %p\n", handle
, iField
, buf
, sz
);
873 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
875 return ERROR_INVALID_HANDLE
;
876 msiobj_lock( &rec
->hdr
);
877 ret
= MSI_RecordReadStream( rec
, iField
, buf
, sz
);
878 msiobj_unlock( &rec
->hdr
);
879 msiobj_release( &rec
->hdr
);
883 UINT
MSI_RecordSetIStream( MSIRECORD
*rec
, UINT iField
, IStream
*stm
)
885 TRACE("%p %d %p\n", rec
, iField
, stm
);
887 if( iField
> rec
->count
)
888 return ERROR_INVALID_FIELD
;
890 MSI_FreeField( &rec
->fields
[iField
] );
892 rec
->fields
[iField
].type
= MSIFIELD_STREAM
;
893 rec
->fields
[iField
].u
.stream
= stm
;
894 IStream_AddRef( stm
);
896 return ERROR_SUCCESS
;
899 UINT
MSI_RecordGetIStream( MSIRECORD
*rec
, UINT iField
, IStream
**pstm
)
901 TRACE("%p %d %p\n", rec
, iField
, pstm
);
903 if( iField
> rec
->count
)
904 return ERROR_INVALID_FIELD
;
906 if( rec
->fields
[iField
].type
!= MSIFIELD_STREAM
)
907 return ERROR_INVALID_FIELD
;
909 *pstm
= rec
->fields
[iField
].u
.stream
;
910 IStream_AddRef( *pstm
);
912 return ERROR_SUCCESS
;
915 static UINT
msi_dump_stream_to_file( IStream
*stm
, LPCWSTR name
)
923 stgm
= STGM_READWRITE
| STGM_SHARE_EXCLUSIVE
| STGM_FAILIFTHERE
;
924 r
= SHCreateStreamOnFileW( name
, stgm
, &out
);
926 return ERROR_FUNCTION_FAILED
;
929 r
= IStream_Seek( stm
, pos
, STREAM_SEEK_END
, &size
);
934 r
= IStream_Seek( stm
, pos
, STREAM_SEEK_SET
, NULL
);
938 r
= IStream_CopyTo( stm
, out
, size
, NULL
, NULL
);
941 IStream_Release( out
);
943 return ERROR_FUNCTION_FAILED
;
944 return ERROR_SUCCESS
;
947 UINT
MSI_RecordStreamToFile( MSIRECORD
*rec
, UINT iField
, LPCWSTR name
)
952 TRACE("%p %u %s\n", rec
, iField
, debugstr_w(name
));
954 msiobj_lock( &rec
->hdr
);
956 r
= MSI_RecordGetIStream( rec
, iField
, &stm
);
957 if( r
== ERROR_SUCCESS
)
959 r
= msi_dump_stream_to_file( stm
, name
);
960 IStream_Release( stm
);
963 msiobj_unlock( &rec
->hdr
);
968 MSIRECORD
*MSI_CloneRecord(MSIRECORD
*rec
)
973 count
= MSI_RecordGetFieldCount(rec
);
974 clone
= MSI_CreateRecord(count
);
978 for (i
= 0; i
<= count
; i
++)
980 if (rec
->fields
[i
].type
== MSIFIELD_STREAM
)
982 if (FAILED(IStream_Clone(rec
->fields
[i
].u
.stream
,
983 &clone
->fields
[i
].u
.stream
)))
985 msiobj_release(&clone
->hdr
);
988 clone
->fields
[i
].type
= MSIFIELD_STREAM
;
992 r
= MSI_RecordCopyField(rec
, i
, clone
, i
);
993 if (r
!= ERROR_SUCCESS
)
995 msiobj_release(&clone
->hdr
);
1004 BOOL
MSI_RecordsAreFieldsEqual(MSIRECORD
*a
, MSIRECORD
*b
, UINT field
)
1006 if (a
->fields
[field
].type
!= b
->fields
[field
].type
)
1009 switch (a
->fields
[field
].type
)
1015 if (a
->fields
[field
].u
.iVal
!= b
->fields
[field
].u
.iVal
)
1020 if (a
->fields
[field
].len
!= b
->fields
[field
].len
) return FALSE
;
1021 if (memcmp( a
->fields
[field
].u
.szwVal
, b
->fields
[field
].u
.szwVal
,
1022 a
->fields
[field
].len
* sizeof(WCHAR
) )) return FALSE
;
1025 case MSIFIELD_STREAM
:
1033 BOOL
MSI_RecordsAreEqual(MSIRECORD
*a
, MSIRECORD
*b
)
1037 if (a
->count
!= b
->count
)
1040 for (i
= 0; i
<= a
->count
; i
++)
1042 if (!MSI_RecordsAreFieldsEqual( a
, b
, i
))
1049 WCHAR
*msi_dup_record_field( MSIRECORD
*rec
, INT field
)
1055 if (MSI_RecordIsNull( rec
, field
)) return NULL
;
1057 r
= MSI_RecordGetStringW( rec
, field
, NULL
, &sz
);
1058 if (r
!= ERROR_SUCCESS
)
1062 str
= msi_alloc( sz
* sizeof(WCHAR
) );
1063 if (!str
) return NULL
;
1065 r
= MSI_RecordGetStringW( rec
, field
, str
, &sz
);
1066 if (r
!= ERROR_SUCCESS
)
1068 ERR("failed to get string!\n");