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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(msi
);
41 #define MSIFIELD_NULL 0
42 #define MSIFIELD_INT 1
43 #define MSIFIELD_STR 2
44 #define MSIFIELD_WSTR 3
45 #define MSIFIELD_STREAM 4
47 static void MSI_FreeField( MSIFIELD
*field
)
55 HeapFree( GetProcessHeap(), 0, field
->u
.szwVal
);
58 IStream_Release( field
->u
.stream
);
61 ERR("Invalid field type %d\n", field
->type
);
65 static void MSI_CloseRecord( MSIOBJECTHDR
*arg
)
67 MSIRECORD
*rec
= (MSIRECORD
*) arg
;
70 for( i
=0; i
<=rec
->count
; i
++ )
71 MSI_FreeField( &rec
->fields
[i
] );
74 MSIRECORD
*MSI_CreateRecord( unsigned int cParams
)
79 TRACE("%d\n", cParams
);
84 len
= sizeof (MSIRECORD
) + sizeof (MSIFIELD
)*cParams
;
85 rec
= alloc_msiobject( MSIHANDLETYPE_RECORD
, len
, MSI_CloseRecord
);
91 MSIHANDLE WINAPI
MsiCreateRecord( unsigned int cParams
)
96 TRACE("%d\n", cParams
);
98 rec
= MSI_CreateRecord( cParams
);
100 ret
= alloc_msihandle( &rec
->hdr
);
101 msiobj_release( &rec
->hdr
);
105 unsigned int MSI_RecordGetFieldCount( MSIRECORD
*rec
)
110 unsigned int WINAPI
MsiRecordGetFieldCount( MSIHANDLE handle
)
115 TRACE("%ld\n", handle
);
117 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
121 msiobj_lock( &rec
->hdr
);
122 ret
= MSI_RecordGetFieldCount( rec
);
123 msiobj_unlock( &rec
->hdr
);
124 msiobj_release( &rec
->hdr
);
129 static BOOL
string2intW( LPCWSTR str
, int *out
)
134 if( *p
== '-' ) /* skip the minus sign */
138 if( (*p
< '0') || (*p
> '9') )
145 if( str
[0] == '-' ) /* check if it's negative */
152 int MSI_RecordGetInteger( MSIRECORD
*rec
, unsigned int iField
)
156 TRACE("%p %d\n", rec
, iField
);
158 if( iField
> rec
->count
)
159 return MSI_NULL_INTEGER
;
161 switch( rec
->fields
[iField
].type
)
164 return rec
->fields
[iField
].u
.iVal
;
166 if( string2intW( rec
->fields
[iField
].u
.szwVal
, &ret
) )
168 return MSI_NULL_INTEGER
;
173 return MSI_NULL_INTEGER
;
176 int WINAPI
MsiRecordGetInteger( MSIHANDLE handle
, unsigned int iField
)
181 TRACE("%ld %d\n", handle
, iField
);
183 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
185 return MSI_NULL_INTEGER
;
187 msiobj_lock( &rec
->hdr
);
188 ret
= MSI_RecordGetInteger( rec
, iField
);
189 msiobj_unlock( &rec
->hdr
);
190 msiobj_release( &rec
->hdr
);
195 UINT WINAPI
MsiRecordClearData( MSIHANDLE handle
)
200 TRACE("%ld\n", handle
);
202 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
204 return ERROR_INVALID_HANDLE
;
206 msiobj_lock( &rec
->hdr
);
207 for( i
=0; i
<=rec
->count
; i
++)
209 MSI_FreeField( &rec
->fields
[i
] );
210 rec
->fields
[i
].type
= MSIFIELD_NULL
;
211 rec
->fields
[i
].u
.iVal
= 0;
213 msiobj_unlock( &rec
->hdr
);
214 msiobj_release( &rec
->hdr
);
216 return ERROR_SUCCESS
;
219 UINT
MSI_RecordSetInteger( MSIRECORD
*rec
, unsigned int iField
, int iVal
)
221 TRACE("%p %u %d\n", rec
, iField
, iVal
);
223 if( iField
> rec
->count
)
224 return ERROR_INVALID_PARAMETER
;
226 MSI_FreeField( &rec
->fields
[iField
] );
227 rec
->fields
[iField
].type
= MSIFIELD_INT
;
228 rec
->fields
[iField
].u
.iVal
= iVal
;
230 return ERROR_SUCCESS
;
233 UINT WINAPI
MsiRecordSetInteger( MSIHANDLE handle
, unsigned int iField
, int iVal
)
238 TRACE("%ld %u %d\n", handle
, iField
, iVal
);
240 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
242 return ERROR_INVALID_HANDLE
;
244 msiobj_lock( &rec
->hdr
);
245 ret
= MSI_RecordSetInteger( rec
, iField
, iVal
);
246 msiobj_unlock( &rec
->hdr
);
247 msiobj_release( &rec
->hdr
);
251 BOOL
MSI_RecordIsNull( MSIRECORD
*rec
, unsigned int iField
)
255 TRACE("%p %d\n", rec
, iField
);
257 r
= ( iField
> rec
->count
) ||
258 ( rec
->fields
[iField
].type
== MSIFIELD_NULL
);
263 BOOL WINAPI
MsiRecordIsNull( MSIHANDLE handle
, unsigned int iField
)
268 TRACE("%ld %d\n", handle
, iField
);
270 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
273 msiobj_lock( &rec
->hdr
);
274 ret
= MSI_RecordIsNull( rec
, iField
);
275 msiobj_unlock( &rec
->hdr
);
276 msiobj_release( &rec
->hdr
);
281 UINT
MSI_RecordGetStringA(MSIRECORD
*rec
, unsigned int iField
,
282 LPSTR szValue
, DWORD
*pcchValue
)
287 TRACE("%p %d %p %p\n", rec
, iField
, szValue
, pcchValue
);
289 if( iField
> rec
->count
)
290 return ERROR_INVALID_PARAMETER
;
293 switch( rec
->fields
[iField
].type
)
296 wsprintfA(buffer
, "%d", rec
->fields
[iField
].u
.iVal
);
297 len
= lstrlenA( buffer
);
298 lstrcpynA(szValue
, buffer
, *pcchValue
);
301 len
= WideCharToMultiByte( CP_ACP
, 0, rec
->fields
[iField
].u
.szwVal
, -1,
302 NULL
, 0 , NULL
, NULL
);
303 WideCharToMultiByte( CP_ACP
, 0, rec
->fields
[iField
].u
.szwVal
, -1,
304 szValue
, *pcchValue
, NULL
, NULL
);
305 if( *pcchValue
&& len
>*pcchValue
)
306 szValue
[*pcchValue
-1] = 0;
315 ret
= ERROR_INVALID_PARAMETER
;
319 if( *pcchValue
< len
)
320 ret
= ERROR_MORE_DATA
;
326 UINT WINAPI
MsiRecordGetStringA(MSIHANDLE handle
, unsigned int iField
,
327 LPSTR szValue
, DWORD
*pcchValue
)
332 TRACE("%ld %d %p %p\n", handle
, iField
, szValue
, pcchValue
);
334 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
336 return ERROR_INVALID_HANDLE
;
337 msiobj_lock( &rec
->hdr
);
338 ret
= MSI_RecordGetStringA( rec
, iField
, szValue
, pcchValue
);
339 msiobj_unlock( &rec
->hdr
);
340 msiobj_release( &rec
->hdr
);
344 const WCHAR
*MSI_RecordGetString( MSIRECORD
*rec
, unsigned int iField
)
346 if( iField
> rec
->count
)
349 if( rec
->fields
[iField
].type
!= MSIFIELD_WSTR
)
352 return rec
->fields
[iField
].u
.szwVal
;
355 UINT
MSI_RecordGetStringW(MSIRECORD
*rec
, unsigned int iField
,
356 LPWSTR szValue
, DWORD
*pcchValue
)
360 static const WCHAR szFormat
[] = { '%','d',0 };
362 TRACE("%p %d %p %p\n", rec
, iField
, szValue
, pcchValue
);
364 if( iField
> rec
->count
)
365 return ERROR_INVALID_PARAMETER
;
368 switch( rec
->fields
[iField
].type
)
371 wsprintfW(buffer
, szFormat
, rec
->fields
[iField
].u
.iVal
);
372 len
= lstrlenW( buffer
);
373 lstrcpynW(szValue
, buffer
, *pcchValue
);
376 len
= lstrlenW( rec
->fields
[iField
].u
.szwVal
);
377 lstrcpynW(szValue
, rec
->fields
[iField
].u
.szwVal
, *pcchValue
);
387 if( *pcchValue
< len
)
388 ret
= ERROR_MORE_DATA
;
394 UINT WINAPI
MsiRecordGetStringW(MSIHANDLE handle
, unsigned int iField
,
395 LPWSTR szValue
, DWORD
*pcchValue
)
400 TRACE("%ld %d %p %p\n", handle
, iField
, szValue
, pcchValue
);
402 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
404 return ERROR_INVALID_HANDLE
;
406 msiobj_lock( &rec
->hdr
);
407 ret
= MSI_RecordGetStringW( rec
, iField
, szValue
, pcchValue
);
408 msiobj_unlock( &rec
->hdr
);
409 msiobj_release( &rec
->hdr
);
413 static UINT
msi_get_stream_size( IStream
*stm
)
418 r
= IStream_Stat( stm
, &stat
, STATFLAG_NONAME
);
421 return stat
.cbSize
.QuadPart
;
424 UINT
MSI_RecordDataSize(MSIRECORD
*rec
, unsigned int iField
)
426 TRACE("%p %d\n", rec
, iField
);
428 if( iField
> rec
->count
)
431 switch( rec
->fields
[iField
].type
)
436 return lstrlenW( rec
->fields
[iField
].u
.szwVal
);
439 case MSIFIELD_STREAM
:
440 return msi_get_stream_size( rec
->fields
[iField
].u
.stream
);
445 UINT WINAPI
MsiRecordDataSize(MSIHANDLE handle
, unsigned int iField
)
450 TRACE("%ld %d\n", handle
, iField
);
452 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
455 msiobj_lock( &rec
->hdr
);
456 ret
= MSI_RecordDataSize( rec
, iField
);
457 msiobj_unlock( &rec
->hdr
);
458 msiobj_release( &rec
->hdr
);
462 UINT
MSI_RecordSetStringA( MSIRECORD
*rec
, unsigned int iField
, LPCSTR szValue
)
466 TRACE("%p %d %s\n", rec
, iField
, debugstr_a(szValue
));
468 if( iField
> rec
->count
)
469 return ERROR_INVALID_FIELD
;
471 MSI_FreeField( &rec
->fields
[iField
] );
472 if( szValue
&& szValue
[0] )
474 str
= strdupAtoW( szValue
);
475 rec
->fields
[iField
].type
= MSIFIELD_WSTR
;
476 rec
->fields
[iField
].u
.szwVal
= str
;
480 rec
->fields
[iField
].type
= MSIFIELD_NULL
;
481 rec
->fields
[iField
].u
.szwVal
= NULL
;
487 UINT WINAPI
MsiRecordSetStringA( MSIHANDLE handle
, unsigned int iField
, LPCSTR szValue
)
492 TRACE("%ld %d %s\n", handle
, iField
, debugstr_a(szValue
));
494 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
496 return ERROR_INVALID_HANDLE
;
497 msiobj_lock( &rec
->hdr
);
498 ret
= MSI_RecordSetStringA( rec
, iField
, szValue
);
499 msiobj_unlock( &rec
->hdr
);
500 msiobj_release( &rec
->hdr
);
504 UINT
MSI_RecordSetStringW( MSIRECORD
*rec
, unsigned int iField
, LPCWSTR szValue
)
508 TRACE("%p %d %s\n", rec
, iField
, debugstr_w(szValue
));
510 if( iField
> rec
->count
)
511 return ERROR_INVALID_FIELD
;
513 MSI_FreeField( &rec
->fields
[iField
] );
515 if( szValue
&& szValue
[0] )
517 str
= strdupW( szValue
);
518 rec
->fields
[iField
].type
= MSIFIELD_WSTR
;
519 rec
->fields
[iField
].u
.szwVal
= str
;
523 rec
->fields
[iField
].type
= MSIFIELD_NULL
;
524 rec
->fields
[iField
].u
.szwVal
= NULL
;
530 UINT WINAPI
MsiRecordSetStringW( MSIHANDLE handle
, unsigned int iField
, LPCWSTR szValue
)
535 TRACE("%ld %d %s\n", handle
, iField
, debugstr_w(szValue
));
537 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
539 return ERROR_INVALID_HANDLE
;
541 msiobj_lock( &rec
->hdr
);
542 ret
= MSI_RecordSetStringW( rec
, iField
, szValue
);
543 msiobj_unlock( &rec
->hdr
);
544 msiobj_release( &rec
->hdr
);
548 /* read the data in a file into an IStream */
549 static UINT
RECORD_StreamFromFile(LPCWSTR szFile
, IStream
**pstm
)
551 DWORD sz
, szHighWord
= 0, read
;
555 ULARGE_INTEGER ulSize
;
557 TRACE("reading %s\n", debugstr_w(szFile
));
559 /* read the file into memory */
560 handle
= CreateFileW(szFile
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
561 if( handle
== INVALID_HANDLE_VALUE
)
562 return GetLastError();
563 sz
= GetFileSize(handle
, &szHighWord
);
564 if( sz
!= INVALID_FILE_SIZE
&& szHighWord
== 0 )
566 hGlob
= GlobalAlloc(GMEM_FIXED
, sz
);
569 BOOL r
= ReadFile(handle
, hGlob
, sz
, &read
, NULL
);
579 return ERROR_FUNCTION_FAILED
;
581 /* make a stream out of it, and set the correct file size */
582 hr
= CreateStreamOnHGlobal(hGlob
, TRUE
, pstm
);
586 return ERROR_FUNCTION_FAILED
;
589 /* set the correct size - CreateStreamOnHGlobal screws it up */
590 ulSize
.QuadPart
= sz
;
591 IStream_SetSize(*pstm
, ulSize
);
593 TRACE("read %s, %ld bytes into IStream %p\n", debugstr_w(szFile
), sz
, *pstm
);
595 return ERROR_SUCCESS
;
598 UINT
MSI_RecordSetStreamW(MSIRECORD
*rec
, unsigned int iField
, LPCWSTR szFilename
)
603 if( (iField
== 0) || (iField
> rec
->count
) )
604 return ERROR_INVALID_PARAMETER
;
606 /* no filename means we should seek back to the start of the stream */
612 if( rec
->fields
[iField
].type
!= MSIFIELD_STREAM
)
613 return ERROR_INVALID_FIELD
;
615 stm
= rec
->fields
[iField
].u
.stream
;
617 return ERROR_INVALID_FIELD
;
620 r
= IStream_Seek( stm
, ofs
, STREAM_SEEK_SET
, &cur
);
622 return ERROR_FUNCTION_FAILED
;
626 /* read the file into a stream and save the stream in the record */
627 r
= RECORD_StreamFromFile(szFilename
, &stm
);
628 if( r
!= ERROR_SUCCESS
)
631 /* if all's good, store it in the record */
632 MSI_FreeField( &rec
->fields
[iField
] );
633 rec
->fields
[iField
].type
= MSIFIELD_STREAM
;
634 rec
->fields
[iField
].u
.stream
= stm
;
637 return ERROR_SUCCESS
;
640 UINT WINAPI
MsiRecordSetStreamA(MSIHANDLE hRecord
, unsigned int iField
, LPCSTR szFilename
)
645 TRACE("%ld %d %s\n", hRecord
, iField
, debugstr_a(szFilename
));
649 wstr
= strdupAtoW( szFilename
);
651 return ERROR_OUTOFMEMORY
;
653 ret
= MsiRecordSetStreamW(hRecord
, iField
, wstr
);
654 HeapFree(GetProcessHeap(),0,wstr
);
659 UINT WINAPI
MsiRecordSetStreamW(MSIHANDLE handle
, unsigned int iField
, LPCWSTR szFilename
)
664 TRACE("%ld %d %s\n", handle
, iField
, debugstr_w(szFilename
));
666 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
668 return ERROR_INVALID_HANDLE
;
670 msiobj_lock( &rec
->hdr
);
671 ret
= MSI_RecordSetStreamW( rec
, iField
, szFilename
);
672 msiobj_unlock( &rec
->hdr
);
673 msiobj_release( &rec
->hdr
);
677 UINT
MSI_RecordReadStream(MSIRECORD
*rec
, unsigned int iField
, char *buf
, DWORD
*sz
)
683 TRACE("%p %d %p %p\n", rec
, iField
, buf
, sz
);
686 return ERROR_INVALID_PARAMETER
;
688 if( iField
> rec
->count
)
689 return ERROR_INVALID_PARAMETER
;
691 if( rec
->fields
[iField
].type
!= MSIFIELD_STREAM
)
692 return ERROR_INVALID_DATATYPE
;
694 stm
= rec
->fields
[iField
].u
.stream
;
696 return ERROR_INVALID_PARAMETER
;
698 /* if there's no buffer pointer, calculate the length to the end */
702 ULARGE_INTEGER end
, cur
;
704 ofs
.QuadPart
= cur
.QuadPart
= 0;
706 r
= IStream_Seek( stm
, ofs
, STREAM_SEEK_SET
, &cur
);
707 IStream_Seek( stm
, ofs
, STREAM_SEEK_END
, &end
);
708 ofs
.QuadPart
= cur
.QuadPart
;
709 IStream_Seek( stm
, ofs
, STREAM_SEEK_SET
, &cur
);
710 *sz
= end
.QuadPart
- cur
.QuadPart
;
712 return ERROR_SUCCESS
;
717 r
= IStream_Read( stm
, buf
, *sz
, &count
);
721 return ERROR_FUNCTION_FAILED
;
726 return ERROR_SUCCESS
;
729 UINT WINAPI
MsiRecordReadStream(MSIHANDLE handle
, unsigned int iField
, char *buf
, DWORD
*sz
)
734 TRACE("%ld %d %p %p\n", handle
, iField
, buf
, sz
);
736 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
738 return ERROR_INVALID_HANDLE
;
739 msiobj_lock( &rec
->hdr
);
740 ret
= MSI_RecordReadStream( rec
, iField
, buf
, sz
);
741 msiobj_unlock( &rec
->hdr
);
742 msiobj_release( &rec
->hdr
);
746 UINT
MSI_RecordSetIStream( MSIRECORD
*rec
, unsigned int iField
, IStream
*stm
)
748 TRACE("%p %d %p\n", rec
, iField
, stm
);
750 if( iField
> rec
->count
)
751 return ERROR_INVALID_FIELD
;
753 MSI_FreeField( &rec
->fields
[iField
] );
755 rec
->fields
[iField
].type
= MSIFIELD_STREAM
;
756 rec
->fields
[iField
].u
.stream
= stm
;
757 IStream_AddRef( stm
);
759 return ERROR_SUCCESS
;
762 UINT
MSI_RecordGetIStream( MSIRECORD
*rec
, unsigned int iField
, IStream
**pstm
)
764 TRACE("%p %d %p\n", rec
, iField
, pstm
);
766 if( iField
> rec
->count
)
767 return ERROR_INVALID_FIELD
;
769 if( rec
->fields
[iField
].type
!= MSIFIELD_STREAM
)
770 return ERROR_INVALID_FIELD
;
772 *pstm
= rec
->fields
[iField
].u
.stream
;
773 IStream_AddRef( *pstm
);
775 return ERROR_SUCCESS
;