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
27 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(msi);
38 #define MSIFIELD_NULL 0
39 #define MSIFIELD_INT 1
40 #define MSIFIELD_STR 2
41 #define MSIFIELD_WSTR 3
42 #define MSIFIELD_STREAM 4
44 void MSI_FreeField( MSIFIELD *field )
52 HeapFree( GetProcessHeap(), 0, field->u.szwVal);
55 IStream_Release( field->u.stream );
58 ERR("Invalid field type %d\n", field->type);
62 void MSI_CloseRecord( MSIOBJECTHDR *arg )
64 MSIRECORD *rec = (MSIRECORD *) arg;
67 for( i=0; i<=rec->count; i++ )
68 MSI_FreeField( &rec->fields[i] );
71 MSIRECORD *MSI_CreateRecord( unsigned int cParams )
76 TRACE("%d\n", cParams);
78 len = sizeof (MSIRECORD) + sizeof (MSIFIELD)*cParams;
79 rec = alloc_msiobject( MSIHANDLETYPE_RECORD, len, MSI_CloseRecord );
85 MSIHANDLE WINAPI MsiCreateRecord( unsigned int cParams )
90 TRACE("%d\n", cParams);
92 rec = MSI_CreateRecord( cParams );
94 ret = alloc_msihandle( &rec->hdr );
98 unsigned int MSI_RecordGetFieldCount( MSIRECORD *rec )
103 unsigned int WINAPI MsiRecordGetFieldCount( MSIHANDLE handle )
108 TRACE("%ld\n", handle );
110 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
113 ERR("Record not found!\n");
117 ret = MSI_RecordGetFieldCount( rec );
118 msiobj_release( &rec->hdr );
123 static BOOL string2intW( LPCWSTR str, int *out )
128 if( *p == '-' ) /* skip the minus sign */
132 if( (*p < '0') || (*p > '9') )
139 if( str[0] == '-' ) /* check if it's negative */
146 int MSI_RecordGetInteger( MSIRECORD *rec, unsigned int iField)
150 TRACE("%p %d\n", rec, iField );
152 if( iField > rec->count )
153 return MSI_NULL_INTEGER;
155 switch( rec->fields[iField].type )
158 return rec->fields[iField].u.iVal;
160 if( string2intW( rec->fields[iField].u.szwVal, &ret ) )
162 return MSI_NULL_INTEGER;
167 return MSI_NULL_INTEGER;
170 int WINAPI MsiRecordGetInteger( MSIHANDLE handle, unsigned int iField)
175 TRACE("%ld %d\n", handle, iField );
177 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
179 return MSI_NULL_INTEGER;
181 ret = MSI_RecordGetInteger( rec, iField );
182 msiobj_release( &rec->hdr );
187 UINT WINAPI MsiRecordClearData( MSIHANDLE handle )
192 TRACE("%ld\n", handle );
194 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
196 return ERROR_INVALID_HANDLE;
198 for( i=0; i<=rec->count; i++)
200 MSI_FreeField( &rec->fields[i] );
201 rec->fields[i].type = MSIFIELD_NULL;
202 rec->fields[i].u.iVal = 0;
205 return ERROR_SUCCESS;
208 UINT MSI_RecordSetInteger( MSIRECORD *rec, unsigned int iField, int iVal )
210 TRACE("%p %u %d\n", rec, iField, iVal);
212 if( iField <= rec->count )
214 MSI_FreeField( &rec->fields[iField] );
215 rec->fields[iField].type = MSIFIELD_INT;
216 rec->fields[iField].u.iVal = iVal;
219 return ERROR_SUCCESS;
222 UINT WINAPI MsiRecordSetInteger( MSIHANDLE handle, unsigned int iField, int iVal )
227 TRACE("%ld %u %d\n", handle, iField, iVal);
229 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
231 return ERROR_INVALID_HANDLE;
233 ret = MSI_RecordSetInteger( rec, iField, iVal );
234 msiobj_release( &rec->hdr );
238 BOOL MSI_RecordIsNull( MSIRECORD *rec, unsigned int iField )
242 TRACE("%p %d\n", rec, iField );
244 r = ( iField > rec->count ) ||
245 ( rec->fields[iField].type == MSIFIELD_NULL );
250 BOOL WINAPI MsiRecordIsNull( MSIHANDLE handle, unsigned int iField )
255 TRACE("%ld %d\n", handle, iField );
257 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
259 return ERROR_INVALID_HANDLE;
260 ret = MSI_RecordIsNull( rec, iField );
261 msiobj_release( &rec->hdr );
266 UINT MSI_RecordGetStringA(MSIRECORD *rec, unsigned int iField,
267 LPSTR szValue, DWORD *pcchValue)
272 TRACE("%p %d %p %p\n", rec, iField, szValue, pcchValue);
274 if( iField > rec->count )
275 return ERROR_INVALID_PARAMETER;
278 switch( rec->fields[iField].type )
281 wsprintfA(buffer, "%d", rec->fields[iField].u.iVal);
282 len = lstrlenA( buffer );
283 lstrcpynA(szValue, buffer, *pcchValue);
286 len = WideCharToMultiByte( CP_ACP, 0, rec->fields[iField].u.szwVal, -1,
287 NULL, 0 , NULL, NULL);
288 WideCharToMultiByte( CP_ACP, 0, rec->fields[iField].u.szwVal, -1,
289 szValue, *pcchValue, NULL, NULL);
296 ret = ERROR_INVALID_PARAMETER;
300 if( *pcchValue < len )
301 ret = ERROR_MORE_DATA;
307 UINT WINAPI MsiRecordGetStringA(MSIHANDLE handle, unsigned int iField,
308 LPSTR szValue, DWORD *pcchValue)
313 TRACE("%ld %d %p %p\n", handle, iField, szValue, pcchValue);
315 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
317 return ERROR_INVALID_HANDLE;
318 ret = MSI_RecordGetStringA( rec, iField, szValue, pcchValue);
319 msiobj_release( &rec->hdr );
323 const WCHAR *MSI_RecordGetString( MSIRECORD *rec, unsigned int iField )
325 if( iField > rec->count )
328 if( rec->fields[iField].type != MSIFIELD_WSTR )
331 return rec->fields[iField].u.szwVal;
334 UINT MSI_RecordGetStringW(MSIRECORD *rec, unsigned int iField,
335 LPWSTR szValue, DWORD *pcchValue)
339 static const WCHAR szFormat[] = { '%','d',0 };
341 TRACE("%p %d %p %p\n", rec, iField, szValue, pcchValue);
343 if( iField > rec->count )
344 return ERROR_INVALID_PARAMETER;
347 switch( rec->fields[iField].type )
350 wsprintfW(buffer, szFormat, rec->fields[iField].u.iVal);
351 len = lstrlenW( buffer );
352 lstrcpynW(szValue, buffer, *pcchValue);
355 len = lstrlenW( rec->fields[iField].u.szwVal );
356 lstrcpynW(szValue, rec->fields[iField].u.szwVal, *pcchValue);
366 if( *pcchValue < len )
367 ret = ERROR_MORE_DATA;
373 UINT WINAPI MsiRecordGetStringW(MSIHANDLE handle, unsigned int iField,
374 LPWSTR szValue, DWORD *pcchValue)
379 TRACE("%ld %d %p %p\n", handle, iField, szValue, pcchValue);
381 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
383 return ERROR_INVALID_HANDLE;
385 ret = MSI_RecordGetStringW( rec, iField, szValue, pcchValue );
386 msiobj_release( &rec->hdr );
390 UINT WINAPI MsiRecordDataSize(MSIHANDLE hRecord, unsigned int iField)
392 FIXME("%ld %d\n", hRecord, iField);
396 UINT MSI_RecordSetStringA( MSIRECORD *rec, unsigned int iField, LPCSTR szValue )
401 TRACE("%p %d %s\n", rec, iField, debugstr_a(szValue));
403 if( iField > rec->count )
404 return ERROR_INVALID_FIELD;
406 len = MultiByteToWideChar( CP_ACP, 0, szValue, -1, NULL, 0 );
407 str = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
408 MultiByteToWideChar( CP_ACP, 0, szValue, -1, str, len );
409 MSI_FreeField( &rec->fields[iField] );
410 rec->fields[iField].type = MSIFIELD_WSTR;
411 rec->fields[iField].u.szwVal = str;
416 UINT WINAPI MsiRecordSetStringA( MSIHANDLE handle, unsigned int iField, LPCSTR szValue )
421 TRACE("%ld %d %s\n", handle, iField, debugstr_a(szValue));
423 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
425 return ERROR_INVALID_HANDLE;
426 ret = MSI_RecordSetStringA( rec, iField, szValue );
427 msiobj_release( &rec->hdr );
431 UINT MSI_RecordSetStringW( MSIRECORD *rec, unsigned int iField, LPCWSTR szValue )
436 TRACE("%p %d %s\n", rec, iField, debugstr_w(szValue));
438 if( iField > rec->count )
439 return ERROR_INVALID_FIELD;
441 len = lstrlenW(szValue) + 1;
442 str = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR));
443 lstrcpyW( str, szValue );
445 MSI_FreeField( &rec->fields[iField] );
446 rec->fields[iField].type = MSIFIELD_WSTR;
447 rec->fields[iField].u.szwVal = str;
452 UINT WINAPI MsiRecordSetStringW( MSIHANDLE handle, unsigned int iField, LPCWSTR szValue )
457 TRACE("%ld %d %s\n", handle, iField, debugstr_w(szValue));
459 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
461 return ERROR_INVALID_HANDLE;
463 ret = MSI_RecordSetStringW( rec, iField, szValue );
464 msiobj_release( &rec->hdr );
468 UINT WINAPI MsiFormatRecordA(MSIHANDLE hInstall, MSIHANDLE hRecord, LPSTR szResult, DWORD *sz)
470 FIXME("%ld %ld %p %p\n", hInstall, hRecord, szResult, sz);
471 return ERROR_CALL_NOT_IMPLEMENTED;
474 UINT WINAPI MsiFormatRecordW(MSIHANDLE hInstall, MSIHANDLE hRecord, LPWSTR szResult, DWORD *sz)
476 FIXME("%ld %ld %p %p\n", hInstall, hRecord, szResult, sz);
477 return ERROR_CALL_NOT_IMPLEMENTED;
480 UINT WINAPI MsiRecordSetStreamA(MSIHANDLE hRecord, unsigned int iField, LPCSTR szFilename)
482 FIXME("%ld %d %s\n", hRecord, iField, debugstr_a(szFilename));
483 return ERROR_CALL_NOT_IMPLEMENTED;
486 UINT WINAPI MsiRecordSetStreamW(MSIHANDLE hRecord, unsigned int iField, LPCWSTR szFilename)
488 FIXME("%ld %d %s\n", hRecord, iField, debugstr_w(szFilename));
489 return ERROR_CALL_NOT_IMPLEMENTED;
492 UINT MSI_RecordReadStream(MSIRECORD *rec, unsigned int iField, char *buf, DWORD *sz)
498 TRACE("%p %d %p %p\n", rec, iField, buf, sz);
500 if( iField > rec->count )
501 return ERROR_INVALID_FIELD;
503 if( rec->fields[iField].type != MSIFIELD_STREAM )
506 return ERROR_INVALID_FIELD;
509 stm = rec->fields[iField].u.stream;
511 return ERROR_INVALID_FIELD;
513 /* if there's no buffer pointer, calculate the length to the end */
517 ULARGE_INTEGER end, cur;
519 ofs.QuadPart = cur.QuadPart = 0;
521 r = IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );
522 IStream_Seek( stm, ofs, STREAM_SEEK_END, &end );
523 ofs.QuadPart = cur.QuadPart;
524 IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );
525 *sz = end.QuadPart - cur.QuadPart;
527 return ERROR_SUCCESS;
532 r = IStream_Read( stm, buf, *sz, &count );
534 return ERROR_FUNCTION_FAILED;
538 return ERROR_SUCCESS;
541 UINT WINAPI MsiRecordReadStream(MSIHANDLE handle, unsigned int iField, char *buf, DWORD *sz)
546 TRACE("%ld %d %p %p\n", handle, iField, buf, sz);
548 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
550 return ERROR_INVALID_HANDLE;
551 ret = MSI_RecordReadStream( rec, iField, buf, sz );
552 msiobj_release( &rec->hdr );
556 UINT MSI_RecordSetIStream( MSIRECORD *rec, unsigned int iField, IStream *stm )
558 TRACE("%p %d %p\n", rec, iField, stm);
560 if( iField > rec->count )
561 return ERROR_INVALID_FIELD;
563 MSI_FreeField( &rec->fields[iField] );
565 rec->fields[iField].type = MSIFIELD_STREAM;
566 rec->fields[iField].u.stream = stm;
567 IStream_AddRef( stm );
569 return ERROR_SUCCESS;