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
)
83 TRACE("%d\n", cParams
);
88 rec
= alloc_msiobject( MSIHANDLETYPE_RECORD
, FIELD_OFFSET(MSIRECORD
, fields
[cParams
+ 1]),
95 MSIHANDLE WINAPI
MsiCreateRecord( UINT cParams
)
100 TRACE("%d\n", cParams
);
102 rec
= MSI_CreateRecord( cParams
);
105 ret
= alloc_msihandle( &rec
->hdr
);
106 msiobj_release( &rec
->hdr
);
111 UINT
MSI_RecordGetFieldCount( const MSIRECORD
*rec
)
116 UINT WINAPI
MsiRecordGetFieldCount( MSIHANDLE handle
)
121 TRACE("%d\n", handle
);
123 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
127 msiobj_lock( &rec
->hdr
);
128 ret
= MSI_RecordGetFieldCount( rec
);
129 msiobj_unlock( &rec
->hdr
);
130 msiobj_release( &rec
->hdr
);
135 static BOOL
string2intW( LPCWSTR str
, int *out
)
140 if( *p
== '-' ) /* skip the minus sign */
144 if( (*p
< '0') || (*p
> '9') )
151 if( str
[0] == '-' ) /* check if it's negative */
158 WCHAR
*msi_strdupW( const WCHAR
*value
, int len
)
162 if (!value
) return NULL
;
163 if (!(ret
= msi_alloc( (len
+ 1) * sizeof(WCHAR
) ))) return NULL
;
164 memcpy( ret
, value
, len
* sizeof(WCHAR
) );
169 UINT
MSI_RecordCopyField( MSIRECORD
*in_rec
, UINT in_n
,
170 MSIRECORD
*out_rec
, UINT out_n
)
172 UINT r
= ERROR_SUCCESS
;
174 msiobj_lock( &in_rec
->hdr
);
176 if ( in_n
> in_rec
->count
|| out_n
> out_rec
->count
)
177 r
= ERROR_FUNCTION_FAILED
;
178 else if ( in_rec
!= out_rec
|| in_n
!= out_n
)
183 in
= &in_rec
->fields
[in_n
];
184 out
= &out_rec
->fields
[out_n
];
191 out
->u
.iVal
= in
->u
.iVal
;
193 case MSIFIELD_INTPTR
:
194 out
->u
.pVal
= in
->u
.pVal
;
197 if ((str
= msi_strdupW( in
->u
.szwVal
, in
->len
)))
202 else r
= ERROR_OUTOFMEMORY
;
204 case MSIFIELD_STREAM
:
205 IStream_AddRef( in
->u
.stream
);
206 out
->u
.stream
= in
->u
.stream
;
209 ERR("invalid field type %d\n", in
->type
);
211 if (r
== ERROR_SUCCESS
)
212 out
->type
= in
->type
;
215 msiobj_unlock( &in_rec
->hdr
);
219 INT_PTR
MSI_RecordGetIntPtr( MSIRECORD
*rec
, UINT iField
)
223 TRACE( "%p %d\n", rec
, iField
);
225 if( iField
> rec
->count
)
228 switch( rec
->fields
[iField
].type
)
231 return rec
->fields
[iField
].u
.iVal
;
232 case MSIFIELD_INTPTR
:
233 return rec
->fields
[iField
].u
.pVal
;
235 if( string2intW( rec
->fields
[iField
].u
.szwVal
, &ret
) )
245 int MSI_RecordGetInteger( MSIRECORD
*rec
, UINT iField
)
249 TRACE("%p %d\n", rec
, iField
);
251 if( iField
> rec
->count
)
252 return MSI_NULL_INTEGER
;
254 switch( rec
->fields
[iField
].type
)
257 return rec
->fields
[iField
].u
.iVal
;
258 case MSIFIELD_INTPTR
:
259 return rec
->fields
[iField
].u
.pVal
;
261 if( string2intW( rec
->fields
[iField
].u
.szwVal
, &ret
) )
263 return MSI_NULL_INTEGER
;
268 return MSI_NULL_INTEGER
;
271 int WINAPI
MsiRecordGetInteger( MSIHANDLE handle
, UINT iField
)
276 TRACE("%d %d\n", handle
, iField
);
278 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
280 return MSI_NULL_INTEGER
;
282 msiobj_lock( &rec
->hdr
);
283 ret
= MSI_RecordGetInteger( rec
, iField
);
284 msiobj_unlock( &rec
->hdr
);
285 msiobj_release( &rec
->hdr
);
290 UINT WINAPI
MsiRecordClearData( MSIHANDLE handle
)
295 TRACE("%d\n", handle
);
297 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
299 return ERROR_INVALID_HANDLE
;
301 msiobj_lock( &rec
->hdr
);
302 for( i
=0; i
<=rec
->count
; i
++)
304 MSI_FreeField( &rec
->fields
[i
] );
305 rec
->fields
[i
].type
= MSIFIELD_NULL
;
306 rec
->fields
[i
].u
.iVal
= 0;
308 msiobj_unlock( &rec
->hdr
);
309 msiobj_release( &rec
->hdr
);
311 return ERROR_SUCCESS
;
314 UINT
MSI_RecordSetIntPtr( MSIRECORD
*rec
, UINT iField
, INT_PTR pVal
)
316 TRACE("%p %u %ld\n", rec
, iField
, pVal
);
318 if( iField
> rec
->count
)
319 return ERROR_INVALID_PARAMETER
;
321 MSI_FreeField( &rec
->fields
[iField
] );
322 rec
->fields
[iField
].type
= MSIFIELD_INTPTR
;
323 rec
->fields
[iField
].u
.pVal
= pVal
;
325 return ERROR_SUCCESS
;
328 UINT
MSI_RecordSetInteger( MSIRECORD
*rec
, UINT iField
, int iVal
)
330 TRACE("%p %u %d\n", rec
, iField
, iVal
);
332 if( iField
> rec
->count
)
333 return ERROR_INVALID_PARAMETER
;
335 MSI_FreeField( &rec
->fields
[iField
] );
337 if (iVal
== MSI_NULL_INTEGER
)
339 rec
->fields
[iField
].type
= MSIFIELD_NULL
;
340 rec
->fields
[iField
].u
.szwVal
= NULL
;
344 rec
->fields
[iField
].type
= MSIFIELD_INT
;
345 rec
->fields
[iField
].u
.iVal
= iVal
;
348 return ERROR_SUCCESS
;
351 UINT WINAPI
MsiRecordSetInteger( MSIHANDLE handle
, UINT iField
, int iVal
)
356 TRACE("%d %u %d\n", handle
, iField
, iVal
);
358 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
360 return ERROR_INVALID_HANDLE
;
362 msiobj_lock( &rec
->hdr
);
363 ret
= MSI_RecordSetInteger( rec
, iField
, iVal
);
364 msiobj_unlock( &rec
->hdr
);
365 msiobj_release( &rec
->hdr
);
369 BOOL
MSI_RecordIsNull( MSIRECORD
*rec
, UINT iField
)
373 TRACE("%p %d\n", rec
, iField
);
375 r
= ( iField
> rec
->count
) ||
376 ( rec
->fields
[iField
].type
== MSIFIELD_NULL
);
381 BOOL WINAPI
MsiRecordIsNull( MSIHANDLE handle
, UINT iField
)
386 TRACE("%d %d\n", handle
, iField
);
388 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
391 msiobj_lock( &rec
->hdr
);
392 ret
= MSI_RecordIsNull( rec
, iField
);
393 msiobj_unlock( &rec
->hdr
);
394 msiobj_release( &rec
->hdr
);
399 UINT
MSI_RecordGetStringA(MSIRECORD
*rec
, UINT iField
,
400 LPSTR szValue
, LPDWORD pcchValue
)
402 UINT len
= 0, ret
= ERROR_SUCCESS
;
405 TRACE("%p %d %p %p\n", rec
, iField
, szValue
, pcchValue
);
407 if( iField
> rec
->count
)
409 if ( szValue
&& *pcchValue
> 0 )
413 return ERROR_SUCCESS
;
416 switch( rec
->fields
[iField
].type
)
419 wsprintfA(buffer
, "%d", rec
->fields
[iField
].u
.iVal
);
420 len
= lstrlenA( buffer
);
422 lstrcpynA(szValue
, buffer
, *pcchValue
);
425 len
= WideCharToMultiByte( CP_ACP
, 0, rec
->fields
[iField
].u
.szwVal
,
426 rec
->fields
[iField
].len
+ 1, NULL
, 0 , NULL
, NULL
);
428 WideCharToMultiByte( CP_ACP
, 0, rec
->fields
[iField
].u
.szwVal
,
429 rec
->fields
[iField
].len
+ 1, szValue
, *pcchValue
, NULL
, NULL
);
430 if( szValue
&& *pcchValue
&& len
>*pcchValue
)
431 szValue
[*pcchValue
-1] = 0;
436 if( szValue
&& *pcchValue
> 0 )
440 ret
= ERROR_INVALID_PARAMETER
;
444 if( szValue
&& *pcchValue
<= len
)
445 ret
= ERROR_MORE_DATA
;
451 UINT WINAPI
MsiRecordGetStringA(MSIHANDLE handle
, UINT iField
,
452 LPSTR szValue
, LPDWORD pcchValue
)
457 TRACE("%d %d %p %p\n", handle
, iField
, szValue
, pcchValue
);
459 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
461 return ERROR_INVALID_HANDLE
;
462 msiobj_lock( &rec
->hdr
);
463 ret
= MSI_RecordGetStringA( rec
, iField
, szValue
, pcchValue
);
464 msiobj_unlock( &rec
->hdr
);
465 msiobj_release( &rec
->hdr
);
469 const WCHAR
*msi_record_get_string( const MSIRECORD
*rec
, UINT field
, int *len
)
471 if (field
> rec
->count
)
474 if (rec
->fields
[field
].type
!= MSIFIELD_WSTR
)
477 if (len
) *len
= rec
->fields
[field
].len
;
479 return rec
->fields
[field
].u
.szwVal
;
482 const WCHAR
*MSI_RecordGetString( const MSIRECORD
*rec
, UINT iField
)
484 return msi_record_get_string( rec
, iField
, NULL
);
487 UINT
MSI_RecordGetStringW(MSIRECORD
*rec
, UINT iField
,
488 LPWSTR szValue
, LPDWORD pcchValue
)
490 static const WCHAR szFormat
[] = {'%','d',0};
491 UINT len
= 0, ret
= ERROR_SUCCESS
;
494 TRACE("%p %d %p %p\n", rec
, iField
, szValue
, pcchValue
);
496 if( iField
> rec
->count
)
498 if ( szValue
&& *pcchValue
> 0 )
502 return ERROR_SUCCESS
;
505 switch( rec
->fields
[iField
].type
)
508 wsprintfW(buffer
, szFormat
, rec
->fields
[iField
].u
.iVal
);
509 len
= lstrlenW( buffer
);
511 lstrcpynW(szValue
, buffer
, *pcchValue
);
514 len
= rec
->fields
[iField
].len
;
516 memcpy( szValue
, rec
->fields
[iField
].u
.szwVal
, min(len
+ 1, *pcchValue
) * sizeof(WCHAR
) );
519 if( szValue
&& *pcchValue
> 0 )
526 if( szValue
&& *pcchValue
<= len
)
527 ret
= ERROR_MORE_DATA
;
533 UINT WINAPI
MsiRecordGetStringW(MSIHANDLE handle
, UINT iField
,
534 LPWSTR szValue
, LPDWORD pcchValue
)
539 TRACE("%d %d %p %p\n", handle
, iField
, szValue
, pcchValue
);
541 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
543 return ERROR_INVALID_HANDLE
;
545 msiobj_lock( &rec
->hdr
);
546 ret
= MSI_RecordGetStringW( rec
, iField
, szValue
, pcchValue
);
547 msiobj_unlock( &rec
->hdr
);
548 msiobj_release( &rec
->hdr
);
552 static UINT
msi_get_stream_size( IStream
*stm
)
557 r
= IStream_Stat( stm
, &stat
, STATFLAG_NONAME
);
560 return stat
.cbSize
.QuadPart
;
563 static UINT
MSI_RecordDataSize(MSIRECORD
*rec
, UINT iField
)
565 TRACE("%p %d\n", rec
, iField
);
567 if( iField
> rec
->count
)
570 switch( rec
->fields
[iField
].type
)
575 return rec
->fields
[iField
].len
;
578 case MSIFIELD_STREAM
:
579 return msi_get_stream_size( rec
->fields
[iField
].u
.stream
);
584 UINT WINAPI
MsiRecordDataSize(MSIHANDLE handle
, UINT iField
)
589 TRACE("%d %d\n", handle
, iField
);
591 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
594 msiobj_lock( &rec
->hdr
);
595 ret
= MSI_RecordDataSize( rec
, iField
);
596 msiobj_unlock( &rec
->hdr
);
597 msiobj_release( &rec
->hdr
);
601 UINT WINAPI
MsiRecordSetStringA( MSIHANDLE handle
, UINT iField
, LPCSTR szValue
)
603 WCHAR
*valueW
= NULL
;
607 TRACE("%d %d %s\n", handle
, iField
, debugstr_a(szValue
));
609 if (szValue
&& !(valueW
= strdupAtoW( szValue
))) return ERROR_OUTOFMEMORY
;
611 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
615 return ERROR_INVALID_HANDLE
;
617 msiobj_lock( &rec
->hdr
);
618 ret
= MSI_RecordSetStringW( rec
, iField
, valueW
);
619 msiobj_unlock( &rec
->hdr
);
620 msiobj_release( &rec
->hdr
);
625 UINT
msi_record_set_string( MSIRECORD
*rec
, UINT field
, const WCHAR
*value
, int len
)
627 if (field
> rec
->count
)
628 return ERROR_INVALID_FIELD
;
630 MSI_FreeField( &rec
->fields
[field
] );
632 if (value
&& len
< 0) len
= strlenW( value
);
636 rec
->fields
[field
].type
= MSIFIELD_WSTR
;
637 rec
->fields
[field
].u
.szwVal
= msi_strdupW( value
, len
);
638 rec
->fields
[field
].len
= len
;
642 rec
->fields
[field
].type
= MSIFIELD_NULL
;
643 rec
->fields
[field
].u
.szwVal
= NULL
;
644 rec
->fields
[field
].len
= 0;
649 UINT
MSI_RecordSetStringW( MSIRECORD
*rec
, UINT iField
, LPCWSTR szValue
)
651 TRACE("%p %d %s\n", rec
, iField
, debugstr_w(szValue
));
653 return msi_record_set_string( rec
, iField
, szValue
, -1 );
656 UINT WINAPI
MsiRecordSetStringW( MSIHANDLE handle
, UINT iField
, LPCWSTR szValue
)
661 TRACE("%d %d %s\n", handle
, iField
, debugstr_w(szValue
));
663 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
665 return ERROR_INVALID_HANDLE
;
667 msiobj_lock( &rec
->hdr
);
668 ret
= MSI_RecordSetStringW( rec
, iField
, szValue
);
669 msiobj_unlock( &rec
->hdr
);
670 msiobj_release( &rec
->hdr
);
674 /* read the data in a file into an IStream */
675 static UINT
RECORD_StreamFromFile(LPCWSTR szFile
, IStream
**pstm
)
677 DWORD sz
, szHighWord
= 0, read
;
681 ULARGE_INTEGER ulSize
;
683 TRACE("reading %s\n", debugstr_w(szFile
));
685 /* read the file into memory */
686 handle
= CreateFileW(szFile
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
687 if( handle
== INVALID_HANDLE_VALUE
)
688 return GetLastError();
689 sz
= GetFileSize(handle
, &szHighWord
);
690 if( sz
!= INVALID_FILE_SIZE
&& szHighWord
== 0 )
692 hGlob
= GlobalAlloc(GMEM_FIXED
, sz
);
695 BOOL r
= ReadFile(handle
, hGlob
, sz
, &read
, NULL
) && read
== sz
;
705 return ERROR_FUNCTION_FAILED
;
707 /* make a stream out of it, and set the correct file size */
708 hr
= CreateStreamOnHGlobal(hGlob
, TRUE
, pstm
);
712 return ERROR_FUNCTION_FAILED
;
715 /* set the correct size - CreateStreamOnHGlobal screws it up */
716 ulSize
.QuadPart
= sz
;
717 IStream_SetSize(*pstm
, ulSize
);
719 TRACE("read %s, %d bytes into IStream %p\n", debugstr_w(szFile
), sz
, *pstm
);
721 return ERROR_SUCCESS
;
724 UINT
MSI_RecordSetStream(MSIRECORD
*rec
, UINT iField
, IStream
*stream
)
726 if ( (iField
== 0) || (iField
> rec
->count
) )
727 return ERROR_INVALID_PARAMETER
;
729 MSI_FreeField( &rec
->fields
[iField
] );
730 rec
->fields
[iField
].type
= MSIFIELD_STREAM
;
731 rec
->fields
[iField
].u
.stream
= stream
;
733 return ERROR_SUCCESS
;
736 UINT
MSI_RecordSetStreamFromFileW(MSIRECORD
*rec
, UINT iField
, LPCWSTR szFilename
)
742 if( (iField
== 0) || (iField
> rec
->count
) )
743 return ERROR_INVALID_PARAMETER
;
745 /* no filename means we should seek back to the start of the stream */
751 if( rec
->fields
[iField
].type
!= MSIFIELD_STREAM
)
752 return ERROR_INVALID_FIELD
;
754 stm
= rec
->fields
[iField
].u
.stream
;
756 return ERROR_INVALID_FIELD
;
759 hr
= IStream_Seek( stm
, ofs
, STREAM_SEEK_SET
, &cur
);
761 return ERROR_FUNCTION_FAILED
;
765 /* read the file into a stream and save the stream in the record */
766 ret
= RECORD_StreamFromFile(szFilename
, &stm
);
767 if (ret
!= ERROR_SUCCESS
)
770 /* if all's good, store it in the record */
771 MSI_RecordSetStream(rec
, iField
, stm
);
774 return ERROR_SUCCESS
;
777 UINT WINAPI
MsiRecordSetStreamA(MSIHANDLE hRecord
, UINT iField
, LPCSTR szFilename
)
782 TRACE("%d %d %s\n", hRecord
, iField
, debugstr_a(szFilename
));
786 wstr
= strdupAtoW( szFilename
);
788 return ERROR_OUTOFMEMORY
;
790 ret
= MsiRecordSetStreamW(hRecord
, iField
, wstr
);
796 UINT WINAPI
MsiRecordSetStreamW(MSIHANDLE handle
, UINT iField
, LPCWSTR szFilename
)
801 TRACE("%d %d %s\n", handle
, iField
, debugstr_w(szFilename
));
803 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
805 return ERROR_INVALID_HANDLE
;
807 msiobj_lock( &rec
->hdr
);
808 ret
= MSI_RecordSetStreamFromFileW( rec
, iField
, szFilename
);
809 msiobj_unlock( &rec
->hdr
);
810 msiobj_release( &rec
->hdr
);
814 UINT
MSI_RecordReadStream(MSIRECORD
*rec
, UINT iField
, char *buf
, LPDWORD sz
)
820 TRACE("%p %d %p %p\n", rec
, iField
, buf
, sz
);
823 return ERROR_INVALID_PARAMETER
;
825 if( iField
> rec
->count
)
826 return ERROR_INVALID_PARAMETER
;
828 if ( rec
->fields
[iField
].type
== MSIFIELD_NULL
)
831 return ERROR_INVALID_DATA
;
834 if( rec
->fields
[iField
].type
!= MSIFIELD_STREAM
)
835 return ERROR_INVALID_DATATYPE
;
837 stm
= rec
->fields
[iField
].u
.stream
;
839 return ERROR_INVALID_PARAMETER
;
841 /* if there's no buffer pointer, calculate the length to the end */
845 ULARGE_INTEGER end
, cur
;
847 ofs
.QuadPart
= cur
.QuadPart
= 0;
849 IStream_Seek( stm
, ofs
, STREAM_SEEK_SET
, &cur
);
850 IStream_Seek( stm
, ofs
, STREAM_SEEK_END
, &end
);
851 ofs
.QuadPart
= cur
.QuadPart
;
852 IStream_Seek( stm
, ofs
, STREAM_SEEK_SET
, &cur
);
853 *sz
= end
.QuadPart
- cur
.QuadPart
;
855 return ERROR_SUCCESS
;
860 r
= IStream_Read( stm
, buf
, *sz
, &count
);
864 return ERROR_FUNCTION_FAILED
;
869 return ERROR_SUCCESS
;
872 UINT WINAPI
MsiRecordReadStream(MSIHANDLE handle
, UINT iField
, char *buf
, LPDWORD sz
)
877 TRACE("%d %d %p %p\n", handle
, iField
, buf
, sz
);
879 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
881 return ERROR_INVALID_HANDLE
;
882 msiobj_lock( &rec
->hdr
);
883 ret
= MSI_RecordReadStream( rec
, iField
, buf
, sz
);
884 msiobj_unlock( &rec
->hdr
);
885 msiobj_release( &rec
->hdr
);
889 UINT
MSI_RecordSetIStream( MSIRECORD
*rec
, UINT iField
, IStream
*stm
)
891 TRACE("%p %d %p\n", rec
, iField
, stm
);
893 if( iField
> rec
->count
)
894 return ERROR_INVALID_FIELD
;
896 MSI_FreeField( &rec
->fields
[iField
] );
898 rec
->fields
[iField
].type
= MSIFIELD_STREAM
;
899 rec
->fields
[iField
].u
.stream
= stm
;
900 IStream_AddRef( stm
);
902 return ERROR_SUCCESS
;
905 UINT
MSI_RecordGetIStream( MSIRECORD
*rec
, UINT iField
, IStream
**pstm
)
907 TRACE("%p %d %p\n", rec
, iField
, pstm
);
909 if( iField
> rec
->count
)
910 return ERROR_INVALID_FIELD
;
912 if( rec
->fields
[iField
].type
!= MSIFIELD_STREAM
)
913 return ERROR_INVALID_FIELD
;
915 *pstm
= rec
->fields
[iField
].u
.stream
;
916 IStream_AddRef( *pstm
);
918 return ERROR_SUCCESS
;
921 static UINT
msi_dump_stream_to_file( IStream
*stm
, LPCWSTR name
)
929 stgm
= STGM_READWRITE
| STGM_SHARE_EXCLUSIVE
| STGM_FAILIFTHERE
;
930 r
= SHCreateStreamOnFileW( name
, stgm
, &out
);
932 return ERROR_FUNCTION_FAILED
;
935 r
= IStream_Seek( stm
, pos
, STREAM_SEEK_END
, &size
);
940 r
= IStream_Seek( stm
, pos
, STREAM_SEEK_SET
, NULL
);
944 r
= IStream_CopyTo( stm
, out
, size
, NULL
, NULL
);
947 IStream_Release( out
);
949 return ERROR_FUNCTION_FAILED
;
950 return ERROR_SUCCESS
;
953 UINT
MSI_RecordStreamToFile( MSIRECORD
*rec
, UINT iField
, LPCWSTR name
)
958 TRACE("%p %u %s\n", rec
, iField
, debugstr_w(name
));
960 msiobj_lock( &rec
->hdr
);
962 r
= MSI_RecordGetIStream( rec
, iField
, &stm
);
963 if( r
== ERROR_SUCCESS
)
965 r
= msi_dump_stream_to_file( stm
, name
);
966 IStream_Release( stm
);
969 msiobj_unlock( &rec
->hdr
);
974 MSIRECORD
*MSI_CloneRecord(MSIRECORD
*rec
)
979 count
= MSI_RecordGetFieldCount(rec
);
980 clone
= MSI_CreateRecord(count
);
984 for (i
= 0; i
<= count
; i
++)
986 if (rec
->fields
[i
].type
== MSIFIELD_STREAM
)
988 if (FAILED(IStream_Clone(rec
->fields
[i
].u
.stream
,
989 &clone
->fields
[i
].u
.stream
)))
991 msiobj_release(&clone
->hdr
);
994 clone
->fields
[i
].type
= MSIFIELD_STREAM
;
998 r
= MSI_RecordCopyField(rec
, i
, clone
, i
);
999 if (r
!= ERROR_SUCCESS
)
1001 msiobj_release(&clone
->hdr
);
1010 BOOL
MSI_RecordsAreFieldsEqual(MSIRECORD
*a
, MSIRECORD
*b
, UINT field
)
1012 if (a
->fields
[field
].type
!= b
->fields
[field
].type
)
1015 switch (a
->fields
[field
].type
)
1021 if (a
->fields
[field
].u
.iVal
!= b
->fields
[field
].u
.iVal
)
1026 if (a
->fields
[field
].len
!= b
->fields
[field
].len
) return FALSE
;
1027 if (memcmp( a
->fields
[field
].u
.szwVal
, b
->fields
[field
].u
.szwVal
,
1028 a
->fields
[field
].len
* sizeof(WCHAR
) )) return FALSE
;
1031 case MSIFIELD_STREAM
:
1039 BOOL
MSI_RecordsAreEqual(MSIRECORD
*a
, MSIRECORD
*b
)
1043 if (a
->count
!= b
->count
)
1046 for (i
= 0; i
<= a
->count
; i
++)
1048 if (!MSI_RecordsAreFieldsEqual( a
, b
, i
))
1055 WCHAR
*msi_dup_record_field( MSIRECORD
*rec
, INT field
)
1061 if (MSI_RecordIsNull( rec
, field
)) return NULL
;
1063 r
= MSI_RecordGetStringW( rec
, field
, NULL
, &sz
);
1064 if (r
!= ERROR_SUCCESS
)
1068 str
= msi_alloc( sz
* sizeof(WCHAR
) );
1069 if (!str
) return NULL
;
1071 r
= MSI_RecordGetStringW( rec
, field
, str
, &sz
);
1072 if (r
!= ERROR_SUCCESS
)
1074 ERR("failed to get string!\n");
1081 void dump_record(MSIRECORD
*rec
)
1091 for (i
= 0; i
<= rec
->count
; i
++)
1093 switch(rec
->fields
[i
].type
)
1095 case MSIFIELD_NULL
: TRACE("(null)"); break;
1096 case MSIFIELD_INT
: TRACE("%d", rec
->fields
[i
].u
.iVal
); break;
1097 case MSIFIELD_WSTR
: TRACE("%s", debugstr_w(rec
->fields
[i
].u
.szwVal
)); break;
1098 case MSIFIELD_INTPTR
: TRACE("%ld", rec
->fields
[i
].u
.pVal
); break;
1099 case MSIFIELD_STREAM
: TRACE("%p", rec
->fields
[i
].u
.stream
); break;
1101 if (i
< rec
->count
) TRACE(", ");