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
50 static void MSI_FreeField( MSIFIELD
*field
)
58 msi_free( field
->u
.szwVal
);
61 IStream_Release( field
->u
.stream
);
64 ERR("Invalid field type %d\n", field
->type
);
68 void MSI_CloseRecord( MSIOBJECTHDR
*arg
)
70 MSIRECORD
*rec
= (MSIRECORD
*) arg
;
73 for( i
=0; i
<=rec
->count
; i
++ )
74 MSI_FreeField( &rec
->fields
[i
] );
77 MSIRECORD
*MSI_CreateRecord( UINT cParams
)
81 TRACE("%d\n", cParams
);
86 rec
= alloc_msiobject( MSIHANDLETYPE_RECORD
, FIELD_OFFSET(MSIRECORD
, fields
[cParams
+ 1]),
93 MSIHANDLE WINAPI
MsiCreateRecord( UINT cParams
)
98 TRACE("%d\n", cParams
);
100 rec
= MSI_CreateRecord( cParams
);
103 ret
= alloc_msihandle( &rec
->hdr
);
104 msiobj_release( &rec
->hdr
);
109 UINT
MSI_RecordGetFieldCount( const MSIRECORD
*rec
)
114 UINT WINAPI
MsiRecordGetFieldCount( MSIHANDLE handle
)
119 TRACE("%d\n", handle
);
121 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
125 msiobj_lock( &rec
->hdr
);
126 ret
= MSI_RecordGetFieldCount( rec
);
127 msiobj_unlock( &rec
->hdr
);
128 msiobj_release( &rec
->hdr
);
133 static BOOL
string2intW( LPCWSTR str
, int *out
)
138 if( *p
== '-' ) /* skip the minus sign */
142 if( (*p
< '0') || (*p
> '9') )
149 if( str
[0] == '-' ) /* check if it's negative */
156 WCHAR
*msi_strdupW( const WCHAR
*value
, int len
)
160 if (!value
) return NULL
;
161 if (!(ret
= msi_alloc( (len
+ 1) * sizeof(WCHAR
) ))) return NULL
;
162 memcpy( ret
, value
, len
* sizeof(WCHAR
) );
167 UINT
MSI_RecordCopyField( MSIRECORD
*in_rec
, UINT in_n
,
168 MSIRECORD
*out_rec
, UINT out_n
)
170 UINT r
= ERROR_SUCCESS
;
172 msiobj_lock( &in_rec
->hdr
);
174 if ( in_n
> in_rec
->count
|| out_n
> out_rec
->count
)
175 r
= ERROR_FUNCTION_FAILED
;
176 else if ( in_rec
!= out_rec
|| in_n
!= out_n
)
181 in
= &in_rec
->fields
[in_n
];
182 out
= &out_rec
->fields
[out_n
];
189 out
->u
.iVal
= in
->u
.iVal
;
192 if ((str
= msi_strdupW( in
->u
.szwVal
, in
->len
)))
197 else r
= ERROR_OUTOFMEMORY
;
199 case MSIFIELD_STREAM
:
200 IStream_AddRef( in
->u
.stream
);
201 out
->u
.stream
= in
->u
.stream
;
204 ERR("invalid field type %d\n", in
->type
);
206 if (r
== ERROR_SUCCESS
)
207 out
->type
= in
->type
;
210 msiobj_unlock( &in_rec
->hdr
);
214 int MSI_RecordGetInteger( MSIRECORD
*rec
, UINT iField
)
218 TRACE("%p %d\n", rec
, iField
);
220 if( iField
> rec
->count
)
221 return MSI_NULL_INTEGER
;
223 switch( rec
->fields
[iField
].type
)
226 return rec
->fields
[iField
].u
.iVal
;
228 if( string2intW( rec
->fields
[iField
].u
.szwVal
, &ret
) )
230 return MSI_NULL_INTEGER
;
235 return MSI_NULL_INTEGER
;
238 int WINAPI
MsiRecordGetInteger( MSIHANDLE handle
, UINT iField
)
243 TRACE("%d %d\n", handle
, iField
);
245 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
247 return MSI_NULL_INTEGER
;
249 msiobj_lock( &rec
->hdr
);
250 ret
= MSI_RecordGetInteger( rec
, iField
);
251 msiobj_unlock( &rec
->hdr
);
252 msiobj_release( &rec
->hdr
);
257 UINT WINAPI
MsiRecordClearData( MSIHANDLE handle
)
262 TRACE("%d\n", handle
);
264 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
266 return ERROR_INVALID_HANDLE
;
268 msiobj_lock( &rec
->hdr
);
269 for( i
=0; i
<=rec
->count
; i
++)
271 MSI_FreeField( &rec
->fields
[i
] );
272 rec
->fields
[i
].type
= MSIFIELD_NULL
;
273 rec
->fields
[i
].u
.iVal
= 0;
275 msiobj_unlock( &rec
->hdr
);
276 msiobj_release( &rec
->hdr
);
278 return ERROR_SUCCESS
;
281 UINT
MSI_RecordSetInteger( MSIRECORD
*rec
, UINT iField
, int iVal
)
283 TRACE("%p %u %d\n", rec
, iField
, iVal
);
285 if( iField
> rec
->count
)
286 return ERROR_INVALID_PARAMETER
;
288 MSI_FreeField( &rec
->fields
[iField
] );
290 if (iVal
== MSI_NULL_INTEGER
)
292 rec
->fields
[iField
].type
= MSIFIELD_NULL
;
293 rec
->fields
[iField
].u
.szwVal
= NULL
;
297 rec
->fields
[iField
].type
= MSIFIELD_INT
;
298 rec
->fields
[iField
].u
.iVal
= iVal
;
301 return ERROR_SUCCESS
;
304 UINT WINAPI
MsiRecordSetInteger( MSIHANDLE handle
, UINT iField
, int iVal
)
309 TRACE("%d %u %d\n", handle
, iField
, iVal
);
311 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
313 return ERROR_INVALID_HANDLE
;
315 msiobj_lock( &rec
->hdr
);
316 ret
= MSI_RecordSetInteger( rec
, iField
, iVal
);
317 msiobj_unlock( &rec
->hdr
);
318 msiobj_release( &rec
->hdr
);
322 BOOL
MSI_RecordIsNull( MSIRECORD
*rec
, UINT iField
)
326 TRACE("%p %d\n", rec
, iField
);
328 r
= ( iField
> rec
->count
) ||
329 ( rec
->fields
[iField
].type
== MSIFIELD_NULL
);
334 BOOL WINAPI
MsiRecordIsNull( MSIHANDLE handle
, UINT iField
)
339 TRACE("%d %d\n", handle
, iField
);
341 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
344 msiobj_lock( &rec
->hdr
);
345 ret
= MSI_RecordIsNull( rec
, iField
);
346 msiobj_unlock( &rec
->hdr
);
347 msiobj_release( &rec
->hdr
);
352 UINT
MSI_RecordGetStringA(MSIRECORD
*rec
, UINT iField
,
353 LPSTR szValue
, LPDWORD pcchValue
)
355 UINT len
= 0, ret
= ERROR_SUCCESS
;
358 TRACE("%p %d %p %p\n", rec
, iField
, szValue
, pcchValue
);
360 if( iField
> rec
->count
)
362 if ( szValue
&& *pcchValue
> 0 )
366 return ERROR_SUCCESS
;
369 switch( rec
->fields
[iField
].type
)
372 wsprintfA(buffer
, "%d", rec
->fields
[iField
].u
.iVal
);
373 len
= lstrlenA( buffer
);
375 lstrcpynA(szValue
, buffer
, *pcchValue
);
378 len
= WideCharToMultiByte( CP_ACP
, 0, rec
->fields
[iField
].u
.szwVal
,
379 rec
->fields
[iField
].len
+ 1, NULL
, 0 , NULL
, NULL
);
381 WideCharToMultiByte( CP_ACP
, 0, rec
->fields
[iField
].u
.szwVal
,
382 rec
->fields
[iField
].len
+ 1, szValue
, *pcchValue
, NULL
, NULL
);
383 if( szValue
&& *pcchValue
&& len
>*pcchValue
)
384 szValue
[*pcchValue
-1] = 0;
389 if( szValue
&& *pcchValue
> 0 )
393 ret
= ERROR_INVALID_PARAMETER
;
397 if( szValue
&& *pcchValue
<= len
)
398 ret
= ERROR_MORE_DATA
;
404 UINT WINAPI
MsiRecordGetStringA(MSIHANDLE handle
, UINT iField
,
405 LPSTR szValue
, LPDWORD pcchValue
)
410 TRACE("%d %d %p %p\n", handle
, iField
, szValue
, pcchValue
);
412 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
414 return ERROR_INVALID_HANDLE
;
415 msiobj_lock( &rec
->hdr
);
416 ret
= MSI_RecordGetStringA( rec
, iField
, szValue
, pcchValue
);
417 msiobj_unlock( &rec
->hdr
);
418 msiobj_release( &rec
->hdr
);
422 const WCHAR
*msi_record_get_string( const MSIRECORD
*rec
, UINT field
, int *len
)
424 if (field
> rec
->count
)
427 if (rec
->fields
[field
].type
!= MSIFIELD_WSTR
)
430 if (len
) *len
= rec
->fields
[field
].len
;
432 return rec
->fields
[field
].u
.szwVal
;
435 const WCHAR
*MSI_RecordGetString( const MSIRECORD
*rec
, UINT iField
)
437 return msi_record_get_string( rec
, iField
, NULL
);
440 UINT
MSI_RecordGetStringW(MSIRECORD
*rec
, UINT iField
,
441 LPWSTR szValue
, LPDWORD pcchValue
)
443 static const WCHAR szFormat
[] = {'%','d',0};
444 UINT len
= 0, ret
= ERROR_SUCCESS
;
447 TRACE("%p %d %p %p\n", rec
, iField
, szValue
, pcchValue
);
449 if( iField
> rec
->count
)
451 if ( szValue
&& *pcchValue
> 0 )
455 return ERROR_SUCCESS
;
458 switch( rec
->fields
[iField
].type
)
461 wsprintfW(buffer
, szFormat
, rec
->fields
[iField
].u
.iVal
);
462 len
= lstrlenW( buffer
);
464 lstrcpynW(szValue
, buffer
, *pcchValue
);
467 len
= rec
->fields
[iField
].len
;
469 memcpy( szValue
, rec
->fields
[iField
].u
.szwVal
, min(len
+ 1, *pcchValue
) * sizeof(WCHAR
) );
472 if( szValue
&& *pcchValue
> 0 )
479 if( szValue
&& *pcchValue
<= len
)
480 ret
= ERROR_MORE_DATA
;
486 UINT WINAPI
MsiRecordGetStringW(MSIHANDLE handle
, UINT iField
,
487 LPWSTR szValue
, LPDWORD pcchValue
)
492 TRACE("%d %d %p %p\n", handle
, iField
, szValue
, pcchValue
);
494 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
496 return ERROR_INVALID_HANDLE
;
498 msiobj_lock( &rec
->hdr
);
499 ret
= MSI_RecordGetStringW( rec
, iField
, szValue
, pcchValue
);
500 msiobj_unlock( &rec
->hdr
);
501 msiobj_release( &rec
->hdr
);
505 static UINT
msi_get_stream_size( IStream
*stm
)
510 r
= IStream_Stat( stm
, &stat
, STATFLAG_NONAME
);
513 return stat
.cbSize
.QuadPart
;
516 static UINT
MSI_RecordDataSize(MSIRECORD
*rec
, UINT iField
)
518 TRACE("%p %d\n", rec
, iField
);
520 if( iField
> rec
->count
)
523 switch( rec
->fields
[iField
].type
)
528 return rec
->fields
[iField
].len
;
531 case MSIFIELD_STREAM
:
532 return msi_get_stream_size( rec
->fields
[iField
].u
.stream
);
537 UINT WINAPI
MsiRecordDataSize(MSIHANDLE handle
, UINT iField
)
542 TRACE("%d %d\n", handle
, iField
);
544 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
547 msiobj_lock( &rec
->hdr
);
548 ret
= MSI_RecordDataSize( rec
, iField
);
549 msiobj_unlock( &rec
->hdr
);
550 msiobj_release( &rec
->hdr
);
554 UINT WINAPI
MsiRecordSetStringA( MSIHANDLE handle
, UINT iField
, LPCSTR szValue
)
556 WCHAR
*valueW
= NULL
;
560 TRACE("%d %d %s\n", handle
, iField
, debugstr_a(szValue
));
562 if (szValue
&& !(valueW
= strdupAtoW( szValue
))) return ERROR_OUTOFMEMORY
;
564 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
568 return ERROR_INVALID_HANDLE
;
570 msiobj_lock( &rec
->hdr
);
571 ret
= MSI_RecordSetStringW( rec
, iField
, valueW
);
572 msiobj_unlock( &rec
->hdr
);
573 msiobj_release( &rec
->hdr
);
578 UINT
msi_record_set_string( MSIRECORD
*rec
, UINT field
, const WCHAR
*value
, int len
)
580 if (field
> rec
->count
)
581 return ERROR_INVALID_FIELD
;
583 MSI_FreeField( &rec
->fields
[field
] );
585 if (value
&& len
< 0) len
= strlenW( value
);
589 rec
->fields
[field
].type
= MSIFIELD_WSTR
;
590 rec
->fields
[field
].u
.szwVal
= msi_strdupW( value
, len
);
591 rec
->fields
[field
].len
= len
;
595 rec
->fields
[field
].type
= MSIFIELD_NULL
;
596 rec
->fields
[field
].u
.szwVal
= NULL
;
597 rec
->fields
[field
].len
= 0;
602 UINT
MSI_RecordSetStringW( MSIRECORD
*rec
, UINT iField
, LPCWSTR szValue
)
604 TRACE("%p %d %s\n", rec
, iField
, debugstr_w(szValue
));
606 return msi_record_set_string( rec
, iField
, szValue
, -1 );
609 UINT WINAPI
MsiRecordSetStringW( MSIHANDLE handle
, UINT iField
, LPCWSTR szValue
)
614 TRACE("%d %d %s\n", handle
, iField
, debugstr_w(szValue
));
616 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
618 return ERROR_INVALID_HANDLE
;
620 msiobj_lock( &rec
->hdr
);
621 ret
= MSI_RecordSetStringW( rec
, iField
, szValue
);
622 msiobj_unlock( &rec
->hdr
);
623 msiobj_release( &rec
->hdr
);
627 /* read the data in a file into an IStream */
628 static UINT
RECORD_StreamFromFile(LPCWSTR szFile
, IStream
**pstm
)
630 DWORD sz
, szHighWord
= 0, read
;
634 ULARGE_INTEGER ulSize
;
636 TRACE("reading %s\n", debugstr_w(szFile
));
638 /* read the file into memory */
639 handle
= CreateFileW(szFile
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
640 if( handle
== INVALID_HANDLE_VALUE
)
641 return GetLastError();
642 sz
= GetFileSize(handle
, &szHighWord
);
643 if( sz
!= INVALID_FILE_SIZE
&& szHighWord
== 0 )
645 hGlob
= GlobalAlloc(GMEM_FIXED
, sz
);
648 BOOL r
= ReadFile(handle
, hGlob
, sz
, &read
, NULL
) && read
== sz
;
658 return ERROR_FUNCTION_FAILED
;
660 /* make a stream out of it, and set the correct file size */
661 hr
= CreateStreamOnHGlobal(hGlob
, TRUE
, pstm
);
665 return ERROR_FUNCTION_FAILED
;
668 /* set the correct size - CreateStreamOnHGlobal screws it up */
669 ulSize
.QuadPart
= sz
;
670 IStream_SetSize(*pstm
, ulSize
);
672 TRACE("read %s, %d bytes into IStream %p\n", debugstr_w(szFile
), sz
, *pstm
);
674 return ERROR_SUCCESS
;
677 UINT
MSI_RecordSetStream(MSIRECORD
*rec
, UINT iField
, IStream
*stream
)
679 if ( (iField
== 0) || (iField
> rec
->count
) )
680 return ERROR_INVALID_PARAMETER
;
682 MSI_FreeField( &rec
->fields
[iField
] );
683 rec
->fields
[iField
].type
= MSIFIELD_STREAM
;
684 rec
->fields
[iField
].u
.stream
= stream
;
686 return ERROR_SUCCESS
;
689 UINT
MSI_RecordSetStreamFromFileW(MSIRECORD
*rec
, UINT iField
, LPCWSTR szFilename
)
695 if( (iField
== 0) || (iField
> rec
->count
) )
696 return ERROR_INVALID_PARAMETER
;
698 /* no filename means we should seek back to the start of the stream */
704 if( rec
->fields
[iField
].type
!= MSIFIELD_STREAM
)
705 return ERROR_INVALID_FIELD
;
707 stm
= rec
->fields
[iField
].u
.stream
;
709 return ERROR_INVALID_FIELD
;
712 hr
= IStream_Seek( stm
, ofs
, STREAM_SEEK_SET
, &cur
);
714 return ERROR_FUNCTION_FAILED
;
718 /* read the file into a stream and save the stream in the record */
719 ret
= RECORD_StreamFromFile(szFilename
, &stm
);
720 if (ret
!= ERROR_SUCCESS
)
723 /* if all's good, store it in the record */
724 MSI_RecordSetStream(rec
, iField
, stm
);
727 return ERROR_SUCCESS
;
730 UINT WINAPI
MsiRecordSetStreamA(MSIHANDLE hRecord
, UINT iField
, LPCSTR szFilename
)
735 TRACE("%d %d %s\n", hRecord
, iField
, debugstr_a(szFilename
));
739 wstr
= strdupAtoW( szFilename
);
741 return ERROR_OUTOFMEMORY
;
743 ret
= MsiRecordSetStreamW(hRecord
, iField
, wstr
);
749 UINT WINAPI
MsiRecordSetStreamW(MSIHANDLE handle
, UINT iField
, LPCWSTR szFilename
)
754 TRACE("%d %d %s\n", handle
, iField
, debugstr_w(szFilename
));
756 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
758 return ERROR_INVALID_HANDLE
;
760 msiobj_lock( &rec
->hdr
);
761 ret
= MSI_RecordSetStreamFromFileW( rec
, iField
, szFilename
);
762 msiobj_unlock( &rec
->hdr
);
763 msiobj_release( &rec
->hdr
);
767 UINT
MSI_RecordReadStream(MSIRECORD
*rec
, UINT iField
, char *buf
, LPDWORD sz
)
773 TRACE("%p %d %p %p\n", rec
, iField
, buf
, sz
);
776 return ERROR_INVALID_PARAMETER
;
778 if( iField
> rec
->count
)
779 return ERROR_INVALID_PARAMETER
;
781 if ( rec
->fields
[iField
].type
== MSIFIELD_NULL
)
784 return ERROR_INVALID_DATA
;
787 if( rec
->fields
[iField
].type
!= MSIFIELD_STREAM
)
788 return ERROR_INVALID_DATATYPE
;
790 stm
= rec
->fields
[iField
].u
.stream
;
792 return ERROR_INVALID_PARAMETER
;
794 /* if there's no buffer pointer, calculate the length to the end */
798 ULARGE_INTEGER end
, cur
;
800 ofs
.QuadPart
= cur
.QuadPart
= 0;
802 IStream_Seek( stm
, ofs
, STREAM_SEEK_SET
, &cur
);
803 IStream_Seek( stm
, ofs
, STREAM_SEEK_END
, &end
);
804 ofs
.QuadPart
= cur
.QuadPart
;
805 IStream_Seek( stm
, ofs
, STREAM_SEEK_SET
, &cur
);
806 *sz
= end
.QuadPart
- cur
.QuadPart
;
808 return ERROR_SUCCESS
;
813 r
= IStream_Read( stm
, buf
, *sz
, &count
);
817 return ERROR_FUNCTION_FAILED
;
822 return ERROR_SUCCESS
;
825 UINT WINAPI
MsiRecordReadStream(MSIHANDLE handle
, UINT iField
, char *buf
, LPDWORD sz
)
830 TRACE("%d %d %p %p\n", handle
, iField
, buf
, sz
);
832 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
834 return ERROR_INVALID_HANDLE
;
835 msiobj_lock( &rec
->hdr
);
836 ret
= MSI_RecordReadStream( rec
, iField
, buf
, sz
);
837 msiobj_unlock( &rec
->hdr
);
838 msiobj_release( &rec
->hdr
);
842 UINT
MSI_RecordSetIStream( MSIRECORD
*rec
, UINT iField
, IStream
*stm
)
844 TRACE("%p %d %p\n", rec
, iField
, stm
);
846 if( iField
> rec
->count
)
847 return ERROR_INVALID_FIELD
;
849 MSI_FreeField( &rec
->fields
[iField
] );
851 rec
->fields
[iField
].type
= MSIFIELD_STREAM
;
852 rec
->fields
[iField
].u
.stream
= stm
;
853 IStream_AddRef( stm
);
855 return ERROR_SUCCESS
;
858 UINT
MSI_RecordGetIStream( MSIRECORD
*rec
, UINT iField
, IStream
**pstm
)
860 TRACE("%p %d %p\n", rec
, iField
, pstm
);
862 if( iField
> rec
->count
)
863 return ERROR_INVALID_FIELD
;
865 if( rec
->fields
[iField
].type
!= MSIFIELD_STREAM
)
866 return ERROR_INVALID_FIELD
;
868 *pstm
= rec
->fields
[iField
].u
.stream
;
869 IStream_AddRef( *pstm
);
871 return ERROR_SUCCESS
;
874 static UINT
msi_dump_stream_to_file( IStream
*stm
, LPCWSTR name
)
882 stgm
= STGM_READWRITE
| STGM_SHARE_EXCLUSIVE
| STGM_FAILIFTHERE
;
883 r
= SHCreateStreamOnFileW( name
, stgm
, &out
);
885 return ERROR_FUNCTION_FAILED
;
888 r
= IStream_Seek( stm
, pos
, STREAM_SEEK_END
, &size
);
893 r
= IStream_Seek( stm
, pos
, STREAM_SEEK_SET
, NULL
);
897 r
= IStream_CopyTo( stm
, out
, size
, NULL
, NULL
);
900 IStream_Release( out
);
902 return ERROR_FUNCTION_FAILED
;
903 return ERROR_SUCCESS
;
906 UINT
MSI_RecordStreamToFile( MSIRECORD
*rec
, UINT iField
, LPCWSTR name
)
911 TRACE("%p %u %s\n", rec
, iField
, debugstr_w(name
));
913 msiobj_lock( &rec
->hdr
);
915 r
= MSI_RecordGetIStream( rec
, iField
, &stm
);
916 if( r
== ERROR_SUCCESS
)
918 r
= msi_dump_stream_to_file( stm
, name
);
919 IStream_Release( stm
);
922 msiobj_unlock( &rec
->hdr
);
927 MSIRECORD
*MSI_CloneRecord(MSIRECORD
*rec
)
932 count
= MSI_RecordGetFieldCount(rec
);
933 clone
= MSI_CreateRecord(count
);
937 for (i
= 0; i
<= count
; i
++)
939 if (rec
->fields
[i
].type
== MSIFIELD_STREAM
)
941 if (FAILED(IStream_Clone(rec
->fields
[i
].u
.stream
,
942 &clone
->fields
[i
].u
.stream
)))
944 msiobj_release(&clone
->hdr
);
947 clone
->fields
[i
].type
= MSIFIELD_STREAM
;
951 r
= MSI_RecordCopyField(rec
, i
, clone
, i
);
952 if (r
!= ERROR_SUCCESS
)
954 msiobj_release(&clone
->hdr
);
963 BOOL
MSI_RecordsAreFieldsEqual(MSIRECORD
*a
, MSIRECORD
*b
, UINT field
)
965 if (a
->fields
[field
].type
!= b
->fields
[field
].type
)
968 switch (a
->fields
[field
].type
)
974 if (a
->fields
[field
].u
.iVal
!= b
->fields
[field
].u
.iVal
)
979 if (a
->fields
[field
].len
!= b
->fields
[field
].len
) return FALSE
;
980 if (memcmp( a
->fields
[field
].u
.szwVal
, b
->fields
[field
].u
.szwVal
,
981 a
->fields
[field
].len
* sizeof(WCHAR
) )) return FALSE
;
984 case MSIFIELD_STREAM
:
992 BOOL
MSI_RecordsAreEqual(MSIRECORD
*a
, MSIRECORD
*b
)
996 if (a
->count
!= b
->count
)
999 for (i
= 0; i
<= a
->count
; i
++)
1001 if (!MSI_RecordsAreFieldsEqual( a
, b
, i
))
1008 WCHAR
*msi_dup_record_field( MSIRECORD
*rec
, INT field
)
1014 if (MSI_RecordIsNull( rec
, field
)) return NULL
;
1016 r
= MSI_RecordGetStringW( rec
, field
, NULL
, &sz
);
1017 if (r
!= ERROR_SUCCESS
)
1021 str
= msi_alloc( sz
* sizeof(WCHAR
) );
1022 if (!str
) return NULL
;
1024 r
= MSI_RecordGetStringW( rec
, field
, str
, &sz
);
1025 if (r
!= ERROR_SUCCESS
)
1027 ERR("failed to get string!\n");
1034 void dump_record(MSIRECORD
*rec
)
1044 for (i
= 0; i
<= rec
->count
; i
++)
1046 switch(rec
->fields
[i
].type
)
1048 case MSIFIELD_NULL
: TRACE("(null)"); break;
1049 case MSIFIELD_INT
: TRACE("%d", rec
->fields
[i
].u
.iVal
); break;
1050 case MSIFIELD_WSTR
: TRACE("%s", debugstr_w(rec
->fields
[i
].u
.szwVal
)); break;
1051 case MSIFIELD_STREAM
: TRACE("%p", rec
->fields
[i
].u
.stream
); break;
1053 if (i
< rec
->count
) TRACE(", ");
1058 UINT
copy_remote_record(const struct wire_record
*in
, MSIHANDLE out
)
1062 UINT r
= ERROR_SUCCESS
;
1064 if (!(rec
= msihandle2msiinfo(out
, MSIHANDLETYPE_RECORD
)))
1065 return ERROR_INVALID_HANDLE
;
1067 rec
->cookie
= in
->cookie
;
1068 for (i
= 0; i
<= in
->count
; i
++)
1070 switch (in
->fields
[i
].type
)
1073 MSI_FreeField(&rec
->fields
[i
]);
1074 rec
->fields
[i
].type
= MSIFIELD_NULL
;
1077 r
= MSI_RecordSetInteger(rec
, i
, in
->fields
[i
].u
.iVal
);
1080 r
= MSI_RecordSetStringW(rec
, i
, in
->fields
[i
].u
.szwVal
);
1082 case MSIFIELD_STREAM
:
1083 r
= MSI_RecordSetIStream(rec
, i
, in
->fields
[i
].u
.stream
);
1086 ERR("invalid field type %d\n", in
->fields
[i
].type
);
1092 msiobj_release(&rec
->hdr
);
1097 msiobj_release(&rec
->hdr
);
1098 return ERROR_SUCCESS
;
1101 UINT
unmarshal_record(const struct wire_record
*in
, MSIHANDLE
*out
)
1106 return ERROR_SUCCESS
;
1109 *out
= MsiCreateRecord(in
->count
);
1110 if (!*out
) return ERROR_OUTOFMEMORY
;
1112 return copy_remote_record(in
, *out
);
1115 struct wire_record
*marshal_record(MSIHANDLE handle
)
1117 struct wire_record
*ret
;
1121 if (!(rec
= msihandle2msiinfo(handle
, MSIHANDLETYPE_RECORD
)))
1124 ret
= midl_user_allocate(sizeof(*ret
) + rec
->count
* sizeof(ret
->fields
[0]));
1125 ret
->count
= rec
->count
;
1126 ret
->cookie
= rec
->cookie
;
1128 for (i
= 0; i
<= rec
->count
; i
++)
1130 switch (rec
->fields
[i
].type
)
1135 ret
->fields
[i
].u
.iVal
= rec
->fields
[i
].u
.iVal
;
1138 ret
->fields
[i
].u
.szwVal
= strdupW(rec
->fields
[i
].u
.szwVal
);
1140 case MSIFIELD_STREAM
:
1141 IStream_AddRef(rec
->fields
[i
].u
.stream
);
1142 ret
->fields
[i
].u
.stream
= rec
->fields
[i
].u
.stream
;
1145 ERR("invalid field type %d\n", rec
->fields
[i
].type
);
1148 ret
->fields
[i
].type
= rec
->fields
[i
].type
;
1151 msiobj_release(&rec
->hdr
);
1155 void free_remote_record(struct wire_record
*rec
)
1159 for (i
= 0; i
<= rec
->count
; i
++)
1161 if (rec
->fields
[i
].type
== MSIFIELD_WSTR
)
1162 midl_user_free(rec
->fields
[i
].u
.szwVal
);
1163 else if (rec
->fields
[i
].type
== MSIFIELD_STREAM
)
1164 IStream_Release(rec
->fields
[i
].u
.stream
);
1167 midl_user_free(rec
);