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"
42 WINE_DEFAULT_DEBUG_CHANNEL(msidb
);
44 #define MSIFIELD_NULL 0
45 #define MSIFIELD_INT 1
46 #define MSIFIELD_WSTR 3
47 #define MSIFIELD_STREAM 4
49 static void MSI_FreeField( MSIFIELD
*field
)
57 free( field
->u
.szwVal
);
60 IStream_Release( field
->u
.stream
);
63 ERR("Invalid field type %d\n", field
->type
);
67 void MSI_CloseRecord( MSIOBJECTHDR
*arg
)
69 MSIRECORD
*rec
= (MSIRECORD
*) arg
;
72 for( i
=0; i
<=rec
->count
; i
++ )
73 MSI_FreeField( &rec
->fields
[i
] );
76 MSIRECORD
*MSI_CreateRecord( UINT cParams
)
80 TRACE("%d\n", cParams
);
85 rec
= alloc_msiobject( MSIHANDLETYPE_RECORD
, FIELD_OFFSET(MSIRECORD
, fields
[cParams
+ 1]),
92 MSIHANDLE WINAPI
MsiCreateRecord( UINT cParams
)
97 TRACE("%d\n", cParams
);
99 rec
= MSI_CreateRecord( cParams
);
102 ret
= alloc_msihandle( &rec
->hdr
);
103 msiobj_release( &rec
->hdr
);
108 UINT
MSI_RecordGetFieldCount( const MSIRECORD
*rec
)
113 UINT WINAPI
MsiRecordGetFieldCount( MSIHANDLE handle
)
118 TRACE( "%lu\n", handle
);
120 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
124 msiobj_lock( &rec
->hdr
);
125 ret
= MSI_RecordGetFieldCount( rec
);
126 msiobj_unlock( &rec
->hdr
);
127 msiobj_release( &rec
->hdr
);
132 static BOOL
string2intW( LPCWSTR str
, int *out
)
137 if( *p
== '-' ) /* skip the minus sign */
141 if( (*p
< '0') || (*p
> '9') )
148 if( str
[0] == '-' ) /* check if it's negative */
155 WCHAR
*msi_strdupW( const WCHAR
*value
, int len
)
159 if (!value
) return NULL
;
160 if (!(ret
= malloc( (len
+ 1) * sizeof(WCHAR
) ))) return NULL
;
161 memcpy( ret
, value
, len
* sizeof(WCHAR
) );
166 UINT
MSI_RecordCopyField( MSIRECORD
*in_rec
, UINT in_n
,
167 MSIRECORD
*out_rec
, UINT out_n
)
169 UINT r
= ERROR_SUCCESS
;
171 msiobj_lock( &in_rec
->hdr
);
173 if ( in_n
> in_rec
->count
|| out_n
> out_rec
->count
)
174 r
= ERROR_FUNCTION_FAILED
;
175 else if ( in_rec
!= out_rec
|| in_n
!= out_n
)
180 in
= &in_rec
->fields
[in_n
];
181 out
= &out_rec
->fields
[out_n
];
188 out
->u
.iVal
= in
->u
.iVal
;
191 if ((str
= msi_strdupW( in
->u
.szwVal
, in
->len
)))
196 else r
= ERROR_OUTOFMEMORY
;
198 case MSIFIELD_STREAM
:
199 IStream_AddRef( in
->u
.stream
);
200 out
->u
.stream
= in
->u
.stream
;
203 ERR("invalid field type %d\n", in
->type
);
205 if (r
== ERROR_SUCCESS
)
206 out
->type
= in
->type
;
209 msiobj_unlock( &in_rec
->hdr
);
213 int MSI_RecordGetInteger( MSIRECORD
*rec
, UINT iField
)
217 TRACE("%p %d\n", rec
, iField
);
219 if( iField
> rec
->count
)
220 return MSI_NULL_INTEGER
;
222 switch( rec
->fields
[iField
].type
)
225 return rec
->fields
[iField
].u
.iVal
;
227 if( string2intW( rec
->fields
[iField
].u
.szwVal
, &ret
) )
229 return MSI_NULL_INTEGER
;
234 return MSI_NULL_INTEGER
;
237 int WINAPI
MsiRecordGetInteger( MSIHANDLE handle
, UINT iField
)
242 TRACE( "%lu, %u\n", handle
, iField
);
244 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
246 return MSI_NULL_INTEGER
;
248 msiobj_lock( &rec
->hdr
);
249 ret
= MSI_RecordGetInteger( rec
, iField
);
250 msiobj_unlock( &rec
->hdr
);
251 msiobj_release( &rec
->hdr
);
256 UINT WINAPI
MsiRecordClearData( MSIHANDLE handle
)
261 TRACE( "%lu\n", handle
);
263 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
265 return ERROR_INVALID_HANDLE
;
267 msiobj_lock( &rec
->hdr
);
268 for( i
=0; i
<=rec
->count
; i
++)
270 MSI_FreeField( &rec
->fields
[i
] );
271 rec
->fields
[i
].type
= MSIFIELD_NULL
;
272 rec
->fields
[i
].u
.iVal
= 0;
274 msiobj_unlock( &rec
->hdr
);
275 msiobj_release( &rec
->hdr
);
277 return ERROR_SUCCESS
;
280 UINT
MSI_RecordSetInteger( MSIRECORD
*rec
, UINT iField
, int iVal
)
282 TRACE("%p %u %d\n", rec
, iField
, iVal
);
284 if( iField
> rec
->count
)
285 return ERROR_INVALID_PARAMETER
;
287 MSI_FreeField( &rec
->fields
[iField
] );
289 if (iVal
== MSI_NULL_INTEGER
)
291 rec
->fields
[iField
].type
= MSIFIELD_NULL
;
292 rec
->fields
[iField
].u
.szwVal
= NULL
;
296 rec
->fields
[iField
].type
= MSIFIELD_INT
;
297 rec
->fields
[iField
].u
.iVal
= iVal
;
300 return ERROR_SUCCESS
;
303 UINT WINAPI
MsiRecordSetInteger( MSIHANDLE handle
, UINT iField
, int iVal
)
308 TRACE( "%lu, %u, %d\n", handle
, iField
, iVal
);
310 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
312 return ERROR_INVALID_HANDLE
;
314 msiobj_lock( &rec
->hdr
);
315 ret
= MSI_RecordSetInteger( rec
, iField
, iVal
);
316 msiobj_unlock( &rec
->hdr
);
317 msiobj_release( &rec
->hdr
);
321 BOOL
MSI_RecordIsNull( MSIRECORD
*rec
, UINT iField
)
325 TRACE("%p %d\n", rec
, iField
);
327 r
= ( iField
> rec
->count
) ||
328 ( rec
->fields
[iField
].type
== MSIFIELD_NULL
);
333 BOOL WINAPI
MsiRecordIsNull( MSIHANDLE handle
, UINT iField
)
338 TRACE( "%lu, %u\n", handle
, iField
);
340 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
343 msiobj_lock( &rec
->hdr
);
344 ret
= MSI_RecordIsNull( rec
, iField
);
345 msiobj_unlock( &rec
->hdr
);
346 msiobj_release( &rec
->hdr
);
351 UINT
MSI_RecordGetStringA(MSIRECORD
*rec
, UINT iField
,
352 LPSTR szValue
, LPDWORD pcchValue
)
354 UINT len
= 0, ret
= ERROR_SUCCESS
;
357 TRACE("%p %d %p %p\n", rec
, iField
, szValue
, pcchValue
);
359 if( iField
> rec
->count
)
361 if ( szValue
&& *pcchValue
> 0 )
365 return ERROR_SUCCESS
;
368 switch( rec
->fields
[iField
].type
)
371 wsprintfA(buffer
, "%d", rec
->fields
[iField
].u
.iVal
);
372 len
= lstrlenA( buffer
);
374 lstrcpynA(szValue
, buffer
, *pcchValue
);
377 len
= WideCharToMultiByte( CP_ACP
, 0, rec
->fields
[iField
].u
.szwVal
,
378 rec
->fields
[iField
].len
+ 1, NULL
, 0 , NULL
, NULL
);
380 WideCharToMultiByte( CP_ACP
, 0, rec
->fields
[iField
].u
.szwVal
,
381 rec
->fields
[iField
].len
+ 1, szValue
, *pcchValue
, NULL
, NULL
);
382 if( szValue
&& *pcchValue
&& len
>*pcchValue
)
383 szValue
[*pcchValue
-1] = 0;
388 if( szValue
&& *pcchValue
> 0 )
392 ret
= ERROR_INVALID_PARAMETER
;
396 if( szValue
&& *pcchValue
<= len
)
397 ret
= ERROR_MORE_DATA
;
403 UINT WINAPI
MsiRecordGetStringA( MSIHANDLE handle
, UINT iField
, char *szValue
, DWORD
*pcchValue
)
408 TRACE( "%lu, %d, %p, %p\n", handle
, iField
, szValue
, pcchValue
);
410 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
412 return ERROR_INVALID_HANDLE
;
413 msiobj_lock( &rec
->hdr
);
414 ret
= MSI_RecordGetStringA( rec
, iField
, szValue
, pcchValue
);
415 msiobj_unlock( &rec
->hdr
);
416 msiobj_release( &rec
->hdr
);
420 const WCHAR
*msi_record_get_string( const MSIRECORD
*rec
, UINT field
, int *len
)
422 if (field
> rec
->count
)
425 if (rec
->fields
[field
].type
!= MSIFIELD_WSTR
)
428 if (len
) *len
= rec
->fields
[field
].len
;
430 return rec
->fields
[field
].u
.szwVal
;
433 const WCHAR
*MSI_RecordGetString( const MSIRECORD
*rec
, UINT iField
)
435 return msi_record_get_string( rec
, iField
, NULL
);
438 UINT
MSI_RecordGetStringW( MSIRECORD
*rec
, UINT iField
, WCHAR
*szValue
, DWORD
*pcchValue
)
440 UINT len
= 0, ret
= ERROR_SUCCESS
;
443 TRACE( "%p, %u, %p, %p\n", rec
, iField
, szValue
, pcchValue
);
445 if( iField
> rec
->count
)
447 if ( szValue
&& *pcchValue
> 0 )
451 return ERROR_SUCCESS
;
454 switch( rec
->fields
[iField
].type
)
457 wsprintfW(buffer
, L
"%d", rec
->fields
[iField
].u
.iVal
);
458 len
= lstrlenW( buffer
);
460 lstrcpynW(szValue
, buffer
, *pcchValue
);
463 len
= rec
->fields
[iField
].len
;
465 memcpy( szValue
, rec
->fields
[iField
].u
.szwVal
, min(len
+ 1, *pcchValue
) * sizeof(WCHAR
) );
468 if( szValue
&& *pcchValue
> 0 )
475 if( szValue
&& *pcchValue
<= len
)
476 ret
= ERROR_MORE_DATA
;
482 UINT WINAPI
MsiRecordGetStringW( MSIHANDLE handle
, UINT iField
, WCHAR
*szValue
, DWORD
*pcchValue
)
487 TRACE( "%lu, %u, %p, %p\n", handle
, iField
, szValue
, pcchValue
);
489 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
491 return ERROR_INVALID_HANDLE
;
493 msiobj_lock( &rec
->hdr
);
494 ret
= MSI_RecordGetStringW( rec
, iField
, szValue
, pcchValue
);
495 msiobj_unlock( &rec
->hdr
);
496 msiobj_release( &rec
->hdr
);
500 static UINT
get_stream_size( IStream
*stm
)
505 r
= IStream_Stat( stm
, &stat
, STATFLAG_NONAME
);
508 return stat
.cbSize
.QuadPart
;
511 static UINT
MSI_RecordDataSize(MSIRECORD
*rec
, UINT iField
)
513 TRACE("%p %d\n", rec
, iField
);
515 if( iField
> rec
->count
)
518 switch( rec
->fields
[iField
].type
)
523 return rec
->fields
[iField
].len
;
526 case MSIFIELD_STREAM
:
527 return get_stream_size( rec
->fields
[iField
].u
.stream
);
532 UINT WINAPI
MsiRecordDataSize( MSIHANDLE handle
, UINT iField
)
537 TRACE( "%lu, %u\n", handle
, iField
);
539 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
542 msiobj_lock( &rec
->hdr
);
543 ret
= MSI_RecordDataSize( rec
, iField
);
544 msiobj_unlock( &rec
->hdr
);
545 msiobj_release( &rec
->hdr
);
549 UINT WINAPI
MsiRecordSetStringA( MSIHANDLE handle
, UINT iField
, const char *szValue
)
551 WCHAR
*valueW
= NULL
;
555 TRACE( "%lu, %u %s\n", handle
, iField
, debugstr_a(szValue
) );
557 if (szValue
&& !(valueW
= strdupAtoW( szValue
))) return ERROR_OUTOFMEMORY
;
559 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
563 return ERROR_INVALID_HANDLE
;
565 msiobj_lock( &rec
->hdr
);
566 ret
= MSI_RecordSetStringW( rec
, iField
, valueW
);
567 msiobj_unlock( &rec
->hdr
);
568 msiobj_release( &rec
->hdr
);
573 UINT
msi_record_set_string( MSIRECORD
*rec
, UINT field
, const WCHAR
*value
, int len
)
575 if (field
> rec
->count
)
576 return ERROR_INVALID_FIELD
;
578 MSI_FreeField( &rec
->fields
[field
] );
580 if (value
&& len
< 0) len
= lstrlenW( value
);
584 rec
->fields
[field
].type
= MSIFIELD_WSTR
;
585 rec
->fields
[field
].u
.szwVal
= msi_strdupW( value
, len
);
586 rec
->fields
[field
].len
= len
;
590 rec
->fields
[field
].type
= MSIFIELD_NULL
;
591 rec
->fields
[field
].u
.szwVal
= NULL
;
592 rec
->fields
[field
].len
= 0;
597 UINT
MSI_RecordSetStringW( MSIRECORD
*rec
, UINT iField
, LPCWSTR szValue
)
599 TRACE("%p %d %s\n", rec
, iField
, debugstr_w(szValue
));
601 return msi_record_set_string( rec
, iField
, szValue
, -1 );
604 UINT WINAPI
MsiRecordSetStringW( MSIHANDLE handle
, UINT iField
, const WCHAR
*szValue
)
609 TRACE( "%lu, %u, %s\n", handle
, iField
, debugstr_w(szValue
) );
611 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
613 return ERROR_INVALID_HANDLE
;
615 msiobj_lock( &rec
->hdr
);
616 ret
= MSI_RecordSetStringW( rec
, iField
, szValue
);
617 msiobj_unlock( &rec
->hdr
);
618 msiobj_release( &rec
->hdr
);
622 /* read the data in a file into an IStream */
623 static UINT
RECORD_StreamFromFile(LPCWSTR szFile
, IStream
**pstm
)
625 DWORD sz
, szHighWord
= 0, read
;
629 ULARGE_INTEGER ulSize
;
631 TRACE("reading %s\n", debugstr_w(szFile
));
633 /* read the file into memory */
634 handle
= CreateFileW(szFile
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
635 if( handle
== INVALID_HANDLE_VALUE
)
636 return GetLastError();
637 sz
= GetFileSize(handle
, &szHighWord
);
638 if( sz
!= INVALID_FILE_SIZE
&& szHighWord
== 0 )
640 hGlob
= GlobalAlloc(GMEM_FIXED
, sz
);
643 BOOL r
= ReadFile(handle
, hGlob
, sz
, &read
, NULL
) && read
== sz
;
653 return ERROR_FUNCTION_FAILED
;
655 /* make a stream out of it, and set the correct file size */
656 hr
= CreateStreamOnHGlobal(hGlob
, TRUE
, pstm
);
660 return ERROR_FUNCTION_FAILED
;
663 /* set the correct size - CreateStreamOnHGlobal screws it up */
664 ulSize
.QuadPart
= sz
;
665 IStream_SetSize(*pstm
, ulSize
);
667 TRACE( "read %s, %lu bytes into IStream %p\n", debugstr_w(szFile
), sz
, *pstm
);
668 return ERROR_SUCCESS
;
671 UINT
MSI_RecordSetStream(MSIRECORD
*rec
, UINT iField
, IStream
*stream
)
673 if ( (iField
== 0) || (iField
> rec
->count
) )
674 return ERROR_INVALID_PARAMETER
;
676 MSI_FreeField( &rec
->fields
[iField
] );
677 rec
->fields
[iField
].type
= MSIFIELD_STREAM
;
678 rec
->fields
[iField
].u
.stream
= stream
;
680 return ERROR_SUCCESS
;
683 UINT
MSI_RecordSetStreamFromFileW(MSIRECORD
*rec
, UINT iField
, LPCWSTR szFilename
)
689 if( (iField
== 0) || (iField
> rec
->count
) )
690 return ERROR_INVALID_PARAMETER
;
692 /* no filename means we should seek back to the start of the stream */
698 if( rec
->fields
[iField
].type
!= MSIFIELD_STREAM
)
699 return ERROR_INVALID_FIELD
;
701 stm
= rec
->fields
[iField
].u
.stream
;
703 return ERROR_INVALID_FIELD
;
706 hr
= IStream_Seek( stm
, ofs
, STREAM_SEEK_SET
, &cur
);
708 return ERROR_FUNCTION_FAILED
;
712 /* read the file into a stream and save the stream in the record */
713 ret
= RECORD_StreamFromFile(szFilename
, &stm
);
714 if (ret
!= ERROR_SUCCESS
)
717 /* if all's good, store it in the record */
718 MSI_RecordSetStream(rec
, iField
, stm
);
721 return ERROR_SUCCESS
;
724 UINT WINAPI
MsiRecordSetStreamA( MSIHANDLE hRecord
, UINT iField
, const char *szFilename
)
729 TRACE( "%lu, %u, %s\n", hRecord
, iField
, debugstr_a(szFilename
) );
733 wstr
= strdupAtoW( szFilename
);
735 return ERROR_OUTOFMEMORY
;
737 ret
= MsiRecordSetStreamW(hRecord
, iField
, wstr
);
743 UINT WINAPI
MsiRecordSetStreamW( MSIHANDLE handle
, UINT iField
, const WCHAR
*szFilename
)
748 TRACE( "%lu, %u, %s\n", handle
, iField
, debugstr_w(szFilename
) );
750 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
752 return ERROR_INVALID_HANDLE
;
754 msiobj_lock( &rec
->hdr
);
755 ret
= MSI_RecordSetStreamFromFileW( rec
, iField
, szFilename
);
756 msiobj_unlock( &rec
->hdr
);
757 msiobj_release( &rec
->hdr
);
761 UINT
MSI_RecordReadStream(MSIRECORD
*rec
, UINT iField
, char *buf
, LPDWORD sz
)
767 TRACE("%p %d %p %p\n", rec
, iField
, buf
, sz
);
770 return ERROR_INVALID_PARAMETER
;
772 if( iField
> rec
->count
)
773 return ERROR_INVALID_PARAMETER
;
775 if ( rec
->fields
[iField
].type
== MSIFIELD_NULL
)
778 return ERROR_INVALID_DATA
;
781 if( rec
->fields
[iField
].type
!= MSIFIELD_STREAM
)
782 return ERROR_INVALID_DATATYPE
;
784 stm
= rec
->fields
[iField
].u
.stream
;
786 return ERROR_INVALID_PARAMETER
;
788 /* if there's no buffer pointer, calculate the length to the end */
792 ULARGE_INTEGER end
, cur
;
794 ofs
.QuadPart
= cur
.QuadPart
= 0;
796 IStream_Seek( stm
, ofs
, STREAM_SEEK_SET
, &cur
);
797 IStream_Seek( stm
, ofs
, STREAM_SEEK_END
, &end
);
798 ofs
.QuadPart
= cur
.QuadPart
;
799 IStream_Seek( stm
, ofs
, STREAM_SEEK_SET
, &cur
);
800 *sz
= end
.QuadPart
- cur
.QuadPart
;
802 return ERROR_SUCCESS
;
807 r
= IStream_Read( stm
, buf
, *sz
, &count
);
811 return ERROR_FUNCTION_FAILED
;
816 return ERROR_SUCCESS
;
819 UINT WINAPI
MsiRecordReadStream( MSIHANDLE handle
, UINT iField
, char *buf
, DWORD
*sz
)
824 TRACE( "%lu, %u, %p, %p\n", handle
, iField
, buf
, sz
);
826 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
828 return ERROR_INVALID_HANDLE
;
829 msiobj_lock( &rec
->hdr
);
830 ret
= MSI_RecordReadStream( rec
, iField
, buf
, sz
);
831 msiobj_unlock( &rec
->hdr
);
832 msiobj_release( &rec
->hdr
);
836 UINT
MSI_RecordSetIStream( MSIRECORD
*rec
, UINT iField
, IStream
*stm
)
838 TRACE("%p %d %p\n", rec
, iField
, stm
);
840 if( iField
> rec
->count
)
841 return ERROR_INVALID_FIELD
;
843 MSI_FreeField( &rec
->fields
[iField
] );
845 rec
->fields
[iField
].type
= MSIFIELD_STREAM
;
846 rec
->fields
[iField
].u
.stream
= stm
;
847 IStream_AddRef( stm
);
849 return ERROR_SUCCESS
;
852 UINT
MSI_RecordGetIStream( MSIRECORD
*rec
, UINT iField
, IStream
**pstm
)
854 TRACE("%p %d %p\n", rec
, iField
, pstm
);
856 if( iField
> rec
->count
)
857 return ERROR_INVALID_FIELD
;
859 if( rec
->fields
[iField
].type
!= MSIFIELD_STREAM
)
860 return ERROR_INVALID_FIELD
;
862 *pstm
= rec
->fields
[iField
].u
.stream
;
863 IStream_AddRef( *pstm
);
865 return ERROR_SUCCESS
;
868 static UINT
dump_stream_to_file( IStream
*stm
, const WCHAR
*name
)
876 stgm
= STGM_READWRITE
| STGM_SHARE_EXCLUSIVE
| STGM_FAILIFTHERE
;
877 r
= SHCreateStreamOnFileW( name
, stgm
, &out
);
879 return ERROR_FUNCTION_FAILED
;
882 r
= IStream_Seek( stm
, pos
, STREAM_SEEK_END
, &size
);
887 r
= IStream_Seek( stm
, pos
, STREAM_SEEK_SET
, NULL
);
891 r
= IStream_CopyTo( stm
, out
, size
, NULL
, NULL
);
894 IStream_Release( out
);
896 return ERROR_FUNCTION_FAILED
;
897 return ERROR_SUCCESS
;
900 UINT
MSI_RecordStreamToFile( MSIRECORD
*rec
, UINT iField
, LPCWSTR name
)
905 TRACE("%p %u %s\n", rec
, iField
, debugstr_w(name
));
907 msiobj_lock( &rec
->hdr
);
909 r
= MSI_RecordGetIStream( rec
, iField
, &stm
);
910 if( r
== ERROR_SUCCESS
)
912 r
= dump_stream_to_file( stm
, name
);
913 IStream_Release( stm
);
916 msiobj_unlock( &rec
->hdr
);
921 MSIRECORD
*MSI_CloneRecord(MSIRECORD
*rec
)
926 count
= MSI_RecordGetFieldCount(rec
);
927 clone
= MSI_CreateRecord(count
);
931 for (i
= 0; i
<= count
; i
++)
933 if (rec
->fields
[i
].type
== MSIFIELD_STREAM
)
935 if (FAILED(IStream_Clone(rec
->fields
[i
].u
.stream
,
936 &clone
->fields
[i
].u
.stream
)))
938 msiobj_release(&clone
->hdr
);
941 clone
->fields
[i
].type
= MSIFIELD_STREAM
;
945 r
= MSI_RecordCopyField(rec
, i
, clone
, i
);
946 if (r
!= ERROR_SUCCESS
)
948 msiobj_release(&clone
->hdr
);
957 BOOL
MSI_RecordsAreFieldsEqual(MSIRECORD
*a
, MSIRECORD
*b
, UINT field
)
959 if (a
->fields
[field
].type
!= b
->fields
[field
].type
)
962 switch (a
->fields
[field
].type
)
968 if (a
->fields
[field
].u
.iVal
!= b
->fields
[field
].u
.iVal
)
973 if (a
->fields
[field
].len
!= b
->fields
[field
].len
) return FALSE
;
974 if (memcmp( a
->fields
[field
].u
.szwVal
, b
->fields
[field
].u
.szwVal
,
975 a
->fields
[field
].len
* sizeof(WCHAR
) )) return FALSE
;
978 case MSIFIELD_STREAM
:
986 BOOL
MSI_RecordsAreEqual(MSIRECORD
*a
, MSIRECORD
*b
)
990 if (a
->count
!= b
->count
)
993 for (i
= 0; i
<= a
->count
; i
++)
995 if (!MSI_RecordsAreFieldsEqual( a
, b
, i
))
1002 WCHAR
*msi_dup_record_field( MSIRECORD
*rec
, INT field
)
1008 if (MSI_RecordIsNull( rec
, field
)) return NULL
;
1010 r
= MSI_RecordGetStringW( rec
, field
, NULL
, &sz
);
1011 if (r
!= ERROR_SUCCESS
)
1015 str
= malloc( sz
* sizeof(WCHAR
) );
1016 if (!str
) return NULL
;
1018 r
= MSI_RecordGetStringW( rec
, field
, str
, &sz
);
1019 if (r
!= ERROR_SUCCESS
)
1021 ERR("failed to get string!\n");
1028 void dump_record(MSIRECORD
*rec
)
1038 for (i
= 0; i
<= rec
->count
; i
++)
1040 switch(rec
->fields
[i
].type
)
1042 case MSIFIELD_NULL
: TRACE("(null)"); break;
1043 case MSIFIELD_INT
: TRACE("%d", rec
->fields
[i
].u
.iVal
); break;
1044 case MSIFIELD_WSTR
: TRACE("%s", debugstr_w(rec
->fields
[i
].u
.szwVal
)); break;
1045 case MSIFIELD_STREAM
: TRACE("%p", rec
->fields
[i
].u
.stream
); break;
1047 if (i
< rec
->count
) TRACE(", ");
1052 UINT
copy_remote_record(const struct wire_record
*in
, MSIHANDLE out
)
1056 UINT r
= ERROR_SUCCESS
;
1058 if (!(rec
= msihandle2msiinfo(out
, MSIHANDLETYPE_RECORD
)))
1059 return ERROR_INVALID_HANDLE
;
1061 rec
->cookie
= in
->cookie
;
1062 for (i
= 0; i
<= in
->count
; i
++)
1064 switch (in
->fields
[i
].type
)
1067 MSI_FreeField(&rec
->fields
[i
]);
1068 rec
->fields
[i
].type
= MSIFIELD_NULL
;
1071 r
= MSI_RecordSetInteger(rec
, i
, in
->fields
[i
].u
.iVal
);
1074 r
= MSI_RecordSetStringW(rec
, i
, in
->fields
[i
].u
.szwVal
);
1076 case MSIFIELD_STREAM
:
1077 r
= MSI_RecordSetIStream(rec
, i
, in
->fields
[i
].u
.stream
);
1080 ERR("invalid field type %d\n", in
->fields
[i
].type
);
1086 msiobj_release(&rec
->hdr
);
1091 msiobj_release(&rec
->hdr
);
1092 return ERROR_SUCCESS
;
1095 UINT
unmarshal_record(const struct wire_record
*in
, MSIHANDLE
*out
)
1100 return ERROR_SUCCESS
;
1103 *out
= MsiCreateRecord(in
->count
);
1104 if (!*out
) return ERROR_OUTOFMEMORY
;
1106 return copy_remote_record(in
, *out
);
1109 struct wire_record
*marshal_record(MSIHANDLE handle
)
1111 struct wire_record
*ret
;
1115 if (!(rec
= msihandle2msiinfo(handle
, MSIHANDLETYPE_RECORD
)))
1118 ret
= midl_user_allocate(sizeof(*ret
) + rec
->count
* sizeof(ret
->fields
[0]));
1119 ret
->count
= rec
->count
;
1120 ret
->cookie
= rec
->cookie
;
1122 for (i
= 0; i
<= rec
->count
; i
++)
1124 switch (rec
->fields
[i
].type
)
1129 ret
->fields
[i
].u
.iVal
= rec
->fields
[i
].u
.iVal
;
1132 ret
->fields
[i
].u
.szwVal
= wcsdup(rec
->fields
[i
].u
.szwVal
);
1134 case MSIFIELD_STREAM
:
1135 IStream_AddRef(rec
->fields
[i
].u
.stream
);
1136 ret
->fields
[i
].u
.stream
= rec
->fields
[i
].u
.stream
;
1139 ERR("invalid field type %d\n", rec
->fields
[i
].type
);
1142 ret
->fields
[i
].type
= rec
->fields
[i
].type
;
1145 msiobj_release(&rec
->hdr
);
1149 void free_remote_record(struct wire_record
*rec
)
1153 for (i
= 0; i
<= rec
->count
; i
++)
1155 if (rec
->fields
[i
].type
== MSIFIELD_WSTR
)
1156 midl_user_free(rec
->fields
[i
].u
.szwVal
);
1157 else if (rec
->fields
[i
].type
== MSIFIELD_STREAM
)
1158 IStream_Release(rec
->fields
[i
].u
.stream
);
1161 midl_user_free(rec
);