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 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 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
);
104 unsigned int MSI_RecordGetFieldCount( MSIRECORD
*rec
)
109 unsigned int WINAPI
MsiRecordGetFieldCount( MSIHANDLE handle
)
114 TRACE("%ld\n", handle
);
116 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
120 msiobj_lock( &rec
->hdr
);
121 ret
= MSI_RecordGetFieldCount( rec
);
122 msiobj_unlock( &rec
->hdr
);
123 msiobj_release( &rec
->hdr
);
128 static BOOL
string2intW( LPCWSTR str
, int *out
)
133 if( *p
== '-' ) /* skip the minus sign */
137 if( (*p
< '0') || (*p
> '9') )
144 if( str
[0] == '-' ) /* check if it's negative */
151 int MSI_RecordGetInteger( MSIRECORD
*rec
, unsigned int iField
)
155 TRACE("%p %d\n", rec
, iField
);
157 if( iField
> rec
->count
)
158 return MSI_NULL_INTEGER
;
160 switch( rec
->fields
[iField
].type
)
163 return rec
->fields
[iField
].u
.iVal
;
165 if( string2intW( rec
->fields
[iField
].u
.szwVal
, &ret
) )
167 return MSI_NULL_INTEGER
;
172 return MSI_NULL_INTEGER
;
175 int WINAPI
MsiRecordGetInteger( MSIHANDLE handle
, unsigned int iField
)
180 TRACE("%ld %d\n", handle
, iField
);
182 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
184 return MSI_NULL_INTEGER
;
186 msiobj_lock( &rec
->hdr
);
187 ret
= MSI_RecordGetInteger( rec
, iField
);
188 msiobj_unlock( &rec
->hdr
);
189 msiobj_release( &rec
->hdr
);
194 UINT WINAPI
MsiRecordClearData( MSIHANDLE handle
)
199 TRACE("%ld\n", handle
);
201 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
203 return ERROR_INVALID_HANDLE
;
205 msiobj_lock( &rec
->hdr
);
206 for( i
=0; i
<=rec
->count
; i
++)
208 MSI_FreeField( &rec
->fields
[i
] );
209 rec
->fields
[i
].type
= MSIFIELD_NULL
;
210 rec
->fields
[i
].u
.iVal
= 0;
212 msiobj_unlock( &rec
->hdr
);
214 return ERROR_SUCCESS
;
217 UINT
MSI_RecordSetInteger( MSIRECORD
*rec
, unsigned int iField
, int iVal
)
219 TRACE("%p %u %d\n", rec
, iField
, iVal
);
221 if( iField
> rec
->count
)
222 return ERROR_INVALID_PARAMETER
;
224 MSI_FreeField( &rec
->fields
[iField
] );
225 rec
->fields
[iField
].type
= MSIFIELD_INT
;
226 rec
->fields
[iField
].u
.iVal
= iVal
;
228 return ERROR_SUCCESS
;
231 UINT WINAPI
MsiRecordSetInteger( MSIHANDLE handle
, unsigned int iField
, int iVal
)
236 TRACE("%ld %u %d\n", handle
, iField
, iVal
);
238 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
240 return ERROR_INVALID_HANDLE
;
242 msiobj_lock( &rec
->hdr
);
243 ret
= MSI_RecordSetInteger( rec
, iField
, iVal
);
244 msiobj_unlock( &rec
->hdr
);
245 msiobj_release( &rec
->hdr
);
249 BOOL
MSI_RecordIsNull( MSIRECORD
*rec
, unsigned int iField
)
253 TRACE("%p %d\n", rec
, iField
);
255 r
= ( iField
> rec
->count
) ||
256 ( rec
->fields
[iField
].type
== MSIFIELD_NULL
);
261 BOOL WINAPI
MsiRecordIsNull( MSIHANDLE handle
, unsigned int iField
)
266 TRACE("%ld %d\n", handle
, iField
);
268 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
271 msiobj_lock( &rec
->hdr
);
272 ret
= MSI_RecordIsNull( rec
, iField
);
273 msiobj_unlock( &rec
->hdr
);
274 msiobj_release( &rec
->hdr
);
279 UINT
MSI_RecordGetStringA(MSIRECORD
*rec
, unsigned int iField
,
280 LPSTR szValue
, DWORD
*pcchValue
)
285 TRACE("%p %d %p %p\n", rec
, iField
, szValue
, pcchValue
);
287 if( iField
> rec
->count
)
288 return ERROR_INVALID_PARAMETER
;
291 switch( rec
->fields
[iField
].type
)
294 wsprintfA(buffer
, "%d", rec
->fields
[iField
].u
.iVal
);
295 len
= lstrlenA( buffer
);
296 lstrcpynA(szValue
, buffer
, *pcchValue
);
299 len
= WideCharToMultiByte( CP_ACP
, 0, rec
->fields
[iField
].u
.szwVal
, -1,
300 NULL
, 0 , NULL
, NULL
);
301 WideCharToMultiByte( CP_ACP
, 0, rec
->fields
[iField
].u
.szwVal
, -1,
302 szValue
, *pcchValue
, NULL
, NULL
);
303 if( *pcchValue
&& len
>*pcchValue
)
304 szValue
[*pcchValue
-1] = 0;
313 ret
= ERROR_INVALID_PARAMETER
;
317 if( *pcchValue
< len
)
318 ret
= ERROR_MORE_DATA
;
324 UINT WINAPI
MsiRecordGetStringA(MSIHANDLE handle
, unsigned int iField
,
325 LPSTR szValue
, DWORD
*pcchValue
)
330 TRACE("%ld %d %p %p\n", handle
, iField
, szValue
, pcchValue
);
332 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
334 return ERROR_INVALID_HANDLE
;
335 msiobj_lock( &rec
->hdr
);
336 ret
= MSI_RecordGetStringA( rec
, iField
, szValue
, pcchValue
);
337 msiobj_unlock( &rec
->hdr
);
338 msiobj_release( &rec
->hdr
);
342 const WCHAR
*MSI_RecordGetString( MSIRECORD
*rec
, unsigned int iField
)
344 if( iField
> rec
->count
)
347 if( rec
->fields
[iField
].type
!= MSIFIELD_WSTR
)
350 return rec
->fields
[iField
].u
.szwVal
;
353 UINT
MSI_RecordGetStringW(MSIRECORD
*rec
, unsigned int iField
,
354 LPWSTR szValue
, DWORD
*pcchValue
)
358 static const WCHAR szFormat
[] = { '%','d',0 };
360 TRACE("%p %d %p %p\n", rec
, iField
, szValue
, pcchValue
);
362 if( iField
> rec
->count
)
363 return ERROR_INVALID_PARAMETER
;
366 switch( rec
->fields
[iField
].type
)
369 wsprintfW(buffer
, szFormat
, rec
->fields
[iField
].u
.iVal
);
370 len
= lstrlenW( buffer
);
371 lstrcpynW(szValue
, buffer
, *pcchValue
);
374 len
= lstrlenW( rec
->fields
[iField
].u
.szwVal
);
375 lstrcpynW(szValue
, rec
->fields
[iField
].u
.szwVal
, *pcchValue
);
385 if( *pcchValue
< len
)
386 ret
= ERROR_MORE_DATA
;
392 UINT WINAPI
MsiRecordGetStringW(MSIHANDLE handle
, unsigned int iField
,
393 LPWSTR szValue
, DWORD
*pcchValue
)
398 TRACE("%ld %d %p %p\n", handle
, iField
, szValue
, pcchValue
);
400 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
402 return ERROR_INVALID_HANDLE
;
404 msiobj_lock( &rec
->hdr
);
405 ret
= MSI_RecordGetStringW( rec
, iField
, szValue
, pcchValue
);
406 msiobj_unlock( &rec
->hdr
);
407 msiobj_release( &rec
->hdr
);
411 UINT
MSI_RecordDataSize(MSIRECORD
*rec
, unsigned int iField
)
413 TRACE("%p %d\n", rec
, iField
);
415 if( iField
> rec
->count
)
418 switch( rec
->fields
[iField
].type
)
423 return lstrlenW( rec
->fields
[iField
].u
.szwVal
);
430 UINT WINAPI
MsiRecordDataSize(MSIHANDLE handle
, unsigned int iField
)
435 TRACE("%ld %d\n", handle
, iField
);
437 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
440 msiobj_lock( &rec
->hdr
);
441 ret
= MSI_RecordDataSize( rec
, iField
);
442 msiobj_unlock( &rec
->hdr
);
443 msiobj_release( &rec
->hdr
);
447 UINT
MSI_RecordSetStringA( MSIRECORD
*rec
, unsigned int iField
, LPCSTR szValue
)
452 TRACE("%p %d %s\n", rec
, iField
, debugstr_a(szValue
));
454 if( iField
> rec
->count
)
455 return ERROR_INVALID_FIELD
;
457 len
= MultiByteToWideChar( CP_ACP
, 0, szValue
, -1, NULL
, 0 );
458 str
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof(WCHAR
) );
459 MultiByteToWideChar( CP_ACP
, 0, szValue
, -1, str
, len
);
460 MSI_FreeField( &rec
->fields
[iField
] );
461 rec
->fields
[iField
].type
= MSIFIELD_WSTR
;
462 rec
->fields
[iField
].u
.szwVal
= str
;
467 UINT WINAPI
MsiRecordSetStringA( MSIHANDLE handle
, unsigned int iField
, LPCSTR szValue
)
472 TRACE("%ld %d %s\n", handle
, iField
, debugstr_a(szValue
));
474 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
476 return ERROR_INVALID_HANDLE
;
477 msiobj_lock( &rec
->hdr
);
478 ret
= MSI_RecordSetStringA( rec
, iField
, szValue
);
479 msiobj_unlock( &rec
->hdr
);
480 msiobj_release( &rec
->hdr
);
484 UINT
MSI_RecordSetStringW( MSIRECORD
*rec
, unsigned int iField
, LPCWSTR szValue
)
489 TRACE("%p %d %s\n", rec
, iField
, debugstr_w(szValue
));
491 if( iField
> rec
->count
)
492 return ERROR_INVALID_FIELD
;
494 len
= lstrlenW(szValue
) + 1;
495 str
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof (WCHAR
));
496 lstrcpyW( str
, szValue
);
498 MSI_FreeField( &rec
->fields
[iField
] );
499 rec
->fields
[iField
].type
= MSIFIELD_WSTR
;
500 rec
->fields
[iField
].u
.szwVal
= str
;
505 UINT WINAPI
MsiRecordSetStringW( MSIHANDLE handle
, unsigned int iField
, LPCWSTR szValue
)
510 TRACE("%ld %d %s\n", handle
, iField
, debugstr_w(szValue
));
512 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
514 return ERROR_INVALID_HANDLE
;
516 msiobj_lock( &rec
->hdr
);
517 ret
= MSI_RecordSetStringW( rec
, iField
, szValue
);
518 msiobj_unlock( &rec
->hdr
);
519 msiobj_release( &rec
->hdr
);
523 /* read the data in a file into an IStream */
524 UINT
RECORD_StreamFromFile(LPCWSTR szFile
, IStream
**pstm
)
526 DWORD sz
, szHighWord
= 0, read
;
530 ULARGE_INTEGER ulSize
;
532 TRACE("reading %s\n", debugstr_w(szFile
));
534 /* read the file into memory */
535 handle
= CreateFileW(szFile
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
536 if( handle
== INVALID_HANDLE_VALUE
)
537 return GetLastError();
538 sz
= GetFileSize(handle
, &szHighWord
);
539 if( sz
!= INVALID_FILE_SIZE
&& szHighWord
== 0 )
541 hGlob
= GlobalAlloc(GMEM_FIXED
, sz
);
544 BOOL r
= ReadFile(handle
, hGlob
, sz
, &read
, NULL
);
554 return ERROR_FUNCTION_FAILED
;
556 /* make a stream out of it, and set the correct file size */
557 hr
= CreateStreamOnHGlobal(hGlob
, TRUE
, pstm
);
561 return ERROR_FUNCTION_FAILED
;
564 /* set the correct size - CreateStreamOnHGlobal screws it up */
565 ulSize
.QuadPart
= sz
;
566 IStream_SetSize(*pstm
, ulSize
);
568 TRACE("read %s, %ld bytes into IStream %p\n", debugstr_w(szFile
), sz
, *pstm
);
570 return ERROR_SUCCESS
;
573 UINT
MSI_RecordSetStreamW(MSIRECORD
*rec
, unsigned int iField
, LPCWSTR szFilename
)
578 if( (iField
== 0) || (iField
> rec
->count
) )
579 return ERROR_INVALID_PARAMETER
;
581 /* no filename means we should seek back to the start of the stream */
587 if( rec
->fields
[iField
].type
!= MSIFIELD_STREAM
)
588 return ERROR_INVALID_FIELD
;
590 stm
= rec
->fields
[iField
].u
.stream
;
592 return ERROR_INVALID_FIELD
;
595 r
= IStream_Seek( stm
, ofs
, STREAM_SEEK_SET
, &cur
);
597 return ERROR_FUNCTION_FAILED
;
601 /* read the file into a stream and save the stream in the record */
602 r
= RECORD_StreamFromFile(szFilename
, &stm
);
603 if( r
!= ERROR_SUCCESS
)
606 /* if all's good, store it in the record */
607 MSI_FreeField( &rec
->fields
[iField
] );
608 rec
->fields
[iField
].type
= MSIFIELD_STREAM
;
609 rec
->fields
[iField
].u
.stream
= stm
;
612 return ERROR_SUCCESS
;
615 UINT WINAPI
MsiRecordSetStreamA(MSIHANDLE hRecord
, unsigned int iField
, LPCSTR szFilename
)
620 TRACE("%ld %d %s\n", hRecord
, iField
, debugstr_a(szFilename
));
624 len
= MultiByteToWideChar(CP_ACP
,0,szFilename
,-1,NULL
,0);
625 wstr
= HeapAlloc(GetProcessHeap(),0,len
*sizeof(WCHAR
));
626 MultiByteToWideChar(CP_ACP
,0,szFilename
,-1,wstr
,len
);
628 ret
= MsiRecordSetStreamW(hRecord
, iField
, wstr
);
629 HeapFree(GetProcessHeap(),0,wstr
);
634 UINT WINAPI
MsiRecordSetStreamW(MSIHANDLE handle
, unsigned int iField
, LPCWSTR szFilename
)
639 TRACE("%ld %d %s\n", handle
, iField
, debugstr_w(szFilename
));
641 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
643 return ERROR_INVALID_HANDLE
;
645 msiobj_lock( &rec
->hdr
);
646 ret
= MSI_RecordSetStreamW( rec
, iField
, szFilename
);
647 msiobj_unlock( &rec
->hdr
);
648 msiobj_release( &rec
->hdr
);
652 UINT
MSI_RecordReadStream(MSIRECORD
*rec
, unsigned int iField
, char *buf
, DWORD
*sz
)
658 TRACE("%p %d %p %p\n", rec
, iField
, buf
, sz
);
661 return ERROR_INVALID_PARAMETER
;
663 if( iField
> rec
->count
)
664 return ERROR_INVALID_PARAMETER
;
666 if( rec
->fields
[iField
].type
!= MSIFIELD_STREAM
)
667 return ERROR_INVALID_DATATYPE
;
669 stm
= rec
->fields
[iField
].u
.stream
;
671 return ERROR_INVALID_PARAMETER
;
673 /* if there's no buffer pointer, calculate the length to the end */
677 ULARGE_INTEGER end
, cur
;
679 ofs
.QuadPart
= cur
.QuadPart
= 0;
681 r
= IStream_Seek( stm
, ofs
, STREAM_SEEK_SET
, &cur
);
682 IStream_Seek( stm
, ofs
, STREAM_SEEK_END
, &end
);
683 ofs
.QuadPart
= cur
.QuadPart
;
684 IStream_Seek( stm
, ofs
, STREAM_SEEK_SET
, &cur
);
685 *sz
= end
.QuadPart
- cur
.QuadPart
;
687 return ERROR_SUCCESS
;
692 r
= IStream_Read( stm
, buf
, *sz
, &count
);
696 return ERROR_FUNCTION_FAILED
;
701 return ERROR_SUCCESS
;
704 UINT WINAPI
MsiRecordReadStream(MSIHANDLE handle
, unsigned int iField
, char *buf
, DWORD
*sz
)
709 TRACE("%ld %d %p %p\n", handle
, iField
, buf
, sz
);
711 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
713 return ERROR_INVALID_HANDLE
;
714 msiobj_lock( &rec
->hdr
);
715 ret
= MSI_RecordReadStream( rec
, iField
, buf
, sz
);
716 msiobj_unlock( &rec
->hdr
);
717 msiobj_release( &rec
->hdr
);
721 UINT
MSI_RecordSetIStream( MSIRECORD
*rec
, unsigned int iField
, IStream
*stm
)
723 TRACE("%p %d %p\n", rec
, iField
, stm
);
725 if( iField
> rec
->count
)
726 return ERROR_INVALID_FIELD
;
728 MSI_FreeField( &rec
->fields
[iField
] );
730 rec
->fields
[iField
].type
= MSIFIELD_STREAM
;
731 rec
->fields
[iField
].u
.stream
= stm
;
732 IStream_AddRef( stm
);
734 return ERROR_SUCCESS
;