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"
38 WINE_DEFAULT_DEBUG_CHANNEL(msi);
40 #define MSIFIELD_NULL 0
41 #define MSIFIELD_INT 1
42 #define MSIFIELD_STR 2
43 #define MSIFIELD_WSTR 3
44 #define MSIFIELD_STREAM 4
46 void MSI_FreeField( MSIFIELD *field )
54 HeapFree( GetProcessHeap(), 0, field->u.szwVal);
57 IStream_Release( field->u.stream );
60 ERR("Invalid field type %d\n", field->type);
64 void MSI_CloseRecord( MSIOBJECTHDR *arg )
66 MSIRECORD *rec = (MSIRECORD *) arg;
69 for( i=0; i<=rec->count; i++ )
70 MSI_FreeField( &rec->fields[i] );
73 MSIRECORD *MSI_CreateRecord( unsigned int cParams )
78 TRACE("%d\n", cParams);
80 len = sizeof (MSIRECORD) + sizeof (MSIFIELD)*cParams;
81 rec = alloc_msiobject( MSIHANDLETYPE_RECORD, len, MSI_CloseRecord );
87 MSIHANDLE WINAPI MsiCreateRecord( unsigned int cParams )
92 TRACE("%d\n", cParams);
94 rec = MSI_CreateRecord( cParams );
96 ret = alloc_msihandle( &rec->hdr );
100 unsigned int MSI_RecordGetFieldCount( MSIRECORD *rec )
105 unsigned int WINAPI MsiRecordGetFieldCount( MSIHANDLE handle )
110 TRACE("%ld\n", handle );
112 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
115 ERR("Record not found!\n");
119 ret = MSI_RecordGetFieldCount( rec );
120 msiobj_release( &rec->hdr );
125 static BOOL string2intW( LPCWSTR str, int *out )
130 if( *p == '-' ) /* skip the minus sign */
134 if( (*p < '0') || (*p > '9') )
141 if( str[0] == '-' ) /* check if it's negative */
148 int MSI_RecordGetInteger( MSIRECORD *rec, unsigned int iField)
152 TRACE("%p %d\n", rec, iField );
154 if( iField > rec->count )
155 return MSI_NULL_INTEGER;
157 switch( rec->fields[iField].type )
160 return rec->fields[iField].u.iVal;
162 if( string2intW( rec->fields[iField].u.szwVal, &ret ) )
164 return MSI_NULL_INTEGER;
169 return MSI_NULL_INTEGER;
172 int WINAPI MsiRecordGetInteger( MSIHANDLE handle, unsigned int iField)
177 TRACE("%ld %d\n", handle, iField );
179 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
181 return MSI_NULL_INTEGER;
183 ret = MSI_RecordGetInteger( rec, iField );
184 msiobj_release( &rec->hdr );
189 UINT WINAPI MsiRecordClearData( MSIHANDLE handle )
194 TRACE("%ld\n", handle );
196 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
198 return ERROR_INVALID_HANDLE;
200 for( i=0; i<=rec->count; i++)
202 MSI_FreeField( &rec->fields[i] );
203 rec->fields[i].type = MSIFIELD_NULL;
204 rec->fields[i].u.iVal = 0;
207 return ERROR_SUCCESS;
210 UINT MSI_RecordSetInteger( MSIRECORD *rec, unsigned int iField, int iVal )
212 TRACE("%p %u %d\n", rec, iField, iVal);
214 if( iField <= rec->count )
216 MSI_FreeField( &rec->fields[iField] );
217 rec->fields[iField].type = MSIFIELD_INT;
218 rec->fields[iField].u.iVal = iVal;
221 return ERROR_SUCCESS;
224 UINT WINAPI MsiRecordSetInteger( MSIHANDLE handle, unsigned int iField, int iVal )
229 TRACE("%ld %u %d\n", handle, iField, iVal);
231 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
233 return ERROR_INVALID_HANDLE;
235 ret = MSI_RecordSetInteger( rec, iField, iVal );
236 msiobj_release( &rec->hdr );
240 BOOL MSI_RecordIsNull( MSIRECORD *rec, unsigned int iField )
244 TRACE("%p %d\n", rec, iField );
246 r = ( iField > rec->count ) ||
247 ( rec->fields[iField].type == MSIFIELD_NULL );
252 BOOL WINAPI MsiRecordIsNull( MSIHANDLE handle, unsigned int iField )
257 TRACE("%ld %d\n", handle, iField );
259 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
261 return ERROR_INVALID_HANDLE;
262 ret = MSI_RecordIsNull( rec, iField );
263 msiobj_release( &rec->hdr );
268 UINT MSI_RecordGetStringA(MSIRECORD *rec, unsigned int iField,
269 LPSTR szValue, DWORD *pcchValue)
274 TRACE("%p %d %p %p\n", rec, iField, szValue, pcchValue);
276 if( iField > rec->count )
277 return ERROR_INVALID_PARAMETER;
280 switch( rec->fields[iField].type )
283 wsprintfA(buffer, "%d", rec->fields[iField].u.iVal);
284 len = lstrlenA( buffer );
285 lstrcpynA(szValue, buffer, *pcchValue);
288 len = WideCharToMultiByte( CP_ACP, 0, rec->fields[iField].u.szwVal, -1,
289 NULL, 0 , NULL, NULL);
290 WideCharToMultiByte( CP_ACP, 0, rec->fields[iField].u.szwVal, -1,
291 szValue, *pcchValue, NULL, NULL);
299 ret = ERROR_INVALID_PARAMETER;
303 if( *pcchValue < len )
304 ret = ERROR_MORE_DATA;
310 UINT WINAPI MsiRecordGetStringA(MSIHANDLE handle, unsigned int iField,
311 LPSTR szValue, DWORD *pcchValue)
316 TRACE("%ld %d %p %p\n", handle, iField, szValue, pcchValue);
318 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
320 return ERROR_INVALID_HANDLE;
321 ret = MSI_RecordGetStringA( rec, iField, szValue, pcchValue);
322 msiobj_release( &rec->hdr );
326 const WCHAR *MSI_RecordGetString( MSIRECORD *rec, unsigned int iField )
328 if( iField > rec->count )
331 if( rec->fields[iField].type != MSIFIELD_WSTR )
334 return rec->fields[iField].u.szwVal;
337 UINT MSI_RecordGetStringW(MSIRECORD *rec, unsigned int iField,
338 LPWSTR szValue, DWORD *pcchValue)
342 static const WCHAR szFormat[] = { '%','d',0 };
344 TRACE("%p %d %p %p\n", rec, iField, szValue, pcchValue);
346 if( iField > rec->count )
347 return ERROR_INVALID_PARAMETER;
350 switch( rec->fields[iField].type )
353 wsprintfW(buffer, szFormat, rec->fields[iField].u.iVal);
354 len = lstrlenW( buffer );
355 lstrcpynW(szValue, buffer, *pcchValue);
358 len = lstrlenW( rec->fields[iField].u.szwVal );
359 lstrcpynW(szValue, rec->fields[iField].u.szwVal, *pcchValue);
369 if( *pcchValue < len )
370 ret = ERROR_MORE_DATA;
376 UINT WINAPI MsiRecordGetStringW(MSIHANDLE handle, unsigned int iField,
377 LPWSTR szValue, DWORD *pcchValue)
382 TRACE("%ld %d %p %p\n", handle, iField, szValue, pcchValue);
384 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
386 return ERROR_INVALID_HANDLE;
388 ret = MSI_RecordGetStringW( rec, iField, szValue, pcchValue );
389 msiobj_release( &rec->hdr );
393 UINT WINAPI MsiRecordDataSize(MSIHANDLE hRecord, unsigned int iField)
395 FIXME("%ld %d\n", hRecord, iField);
399 UINT MSI_RecordSetStringA( MSIRECORD *rec, unsigned int iField, LPCSTR szValue )
404 TRACE("%p %d %s\n", rec, iField, debugstr_a(szValue));
406 if( iField > rec->count )
407 return ERROR_INVALID_FIELD;
409 len = MultiByteToWideChar( CP_ACP, 0, szValue, -1, NULL, 0 );
410 str = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
411 MultiByteToWideChar( CP_ACP, 0, szValue, -1, str, len );
412 MSI_FreeField( &rec->fields[iField] );
413 rec->fields[iField].type = MSIFIELD_WSTR;
414 rec->fields[iField].u.szwVal = str;
419 UINT WINAPI MsiRecordSetStringA( MSIHANDLE handle, unsigned int iField, LPCSTR szValue )
424 TRACE("%ld %d %s\n", handle, iField, debugstr_a(szValue));
426 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
428 return ERROR_INVALID_HANDLE;
429 ret = MSI_RecordSetStringA( rec, iField, szValue );
430 msiobj_release( &rec->hdr );
434 UINT MSI_RecordSetStringW( MSIRECORD *rec, unsigned int iField, LPCWSTR szValue )
439 TRACE("%p %d %s\n", rec, iField, debugstr_w(szValue));
441 if( iField > rec->count )
442 return ERROR_INVALID_FIELD;
444 len = lstrlenW(szValue) + 1;
445 str = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR));
446 lstrcpyW( str, szValue );
448 MSI_FreeField( &rec->fields[iField] );
449 rec->fields[iField].type = MSIFIELD_WSTR;
450 rec->fields[iField].u.szwVal = str;
455 UINT WINAPI MsiRecordSetStringW( MSIHANDLE handle, unsigned int iField, LPCWSTR szValue )
460 TRACE("%ld %d %s\n", handle, iField, debugstr_w(szValue));
462 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
464 return ERROR_INVALID_HANDLE;
466 ret = MSI_RecordSetStringW( rec, iField, szValue );
467 msiobj_release( &rec->hdr );
471 UINT WINAPI MsiFormatRecordA(MSIHANDLE hInstall, MSIHANDLE hRecord, LPSTR szResult, DWORD *sz)
473 FIXME("%ld %ld %p %p\n", hInstall, hRecord, szResult, sz);
474 return ERROR_CALL_NOT_IMPLEMENTED;
477 UINT WINAPI MsiFormatRecordW(MSIHANDLE hInstall, MSIHANDLE hRecord, LPWSTR szResult, DWORD *sz)
479 FIXME("%ld %ld %p %p\n", hInstall, hRecord, szResult, sz);
480 return ERROR_CALL_NOT_IMPLEMENTED;
483 UINT WINAPI MsiRecordSetStreamA(MSIHANDLE hRecord, unsigned int iField, LPCSTR szFilename)
485 FIXME("%ld %d %s\n", hRecord, iField, debugstr_a(szFilename));
486 return ERROR_CALL_NOT_IMPLEMENTED;
489 UINT WINAPI MsiRecordSetStreamW(MSIHANDLE hRecord, unsigned int iField, LPCWSTR szFilename)
491 FIXME("%ld %d %s\n", hRecord, iField, debugstr_w(szFilename));
492 return ERROR_CALL_NOT_IMPLEMENTED;
495 UINT MSI_RecordReadStream(MSIRECORD *rec, unsigned int iField, char *buf, DWORD *sz)
501 TRACE("%p %d %p %p\n", rec, iField, buf, sz);
503 if( iField > rec->count )
504 return ERROR_INVALID_FIELD;
506 if( rec->fields[iField].type != MSIFIELD_STREAM )
509 return ERROR_INVALID_FIELD;
512 stm = rec->fields[iField].u.stream;
514 return ERROR_INVALID_FIELD;
516 /* if there's no buffer pointer, calculate the length to the end */
520 ULARGE_INTEGER end, cur;
522 ofs.QuadPart = cur.QuadPart = 0;
524 r = IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );
525 IStream_Seek( stm, ofs, STREAM_SEEK_END, &end );
526 ofs.QuadPart = cur.QuadPart;
527 IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );
528 *sz = end.QuadPart - cur.QuadPart;
530 return ERROR_SUCCESS;
535 r = IStream_Read( stm, buf, *sz, &count );
539 return ERROR_FUNCTION_FAILED;
544 return ERROR_SUCCESS;
547 UINT WINAPI MsiRecordReadStream(MSIHANDLE handle, unsigned int iField, char *buf, DWORD *sz)
552 TRACE("%ld %d %p %p\n", handle, iField, buf, sz);
554 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
556 return ERROR_INVALID_HANDLE;
557 ret = MSI_RecordReadStream( rec, iField, buf, sz );
558 msiobj_release( &rec->hdr );
562 UINT MSI_RecordSetIStream( MSIRECORD *rec, unsigned int iField, IStream *stm )
564 TRACE("%p %d %p\n", rec, iField, stm);
566 if( iField > rec->count )
567 return ERROR_INVALID_FIELD;
569 MSI_FreeField( &rec->fields[iField] );
571 rec->fields[iField].type = MSIFIELD_STREAM;
572 rec->fields[iField].u.stream = stm;
573 IStream_AddRef( stm );
575 return ERROR_SUCCESS;