2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2002 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 /* maybe we can use a Variant instead of doing it ourselves? */
45 typedef struct tagMSIFIELD
56 typedef struct tagMSIRECORD
58 UINT count
; /* as passed to MsiCreateRecord */
59 MSIFIELD fields
[1]; /* nb. array size is count+1 */
62 void MSI_FreeField( MSIFIELD
*field
)
70 HeapFree( GetProcessHeap(), 0, field
->u
.szwVal
);
73 IStream_Release( field
->u
.stream
);
76 ERR("Invalid field type %d\n", field
->type
);
80 void MSI_CloseRecord( VOID
*arg
)
82 MSIRECORD
*rec
= (MSIRECORD
*) arg
;
85 for( i
=0; i
<=rec
->count
; i
++ )
86 MSI_FreeField( &rec
->fields
[i
] );
89 MSIHANDLE WINAPI
MsiCreateRecord( unsigned int cParams
)
95 TRACE("%d\n", cParams
);
97 sz
= sizeof (MSIRECORD
) + sizeof(MSIFIELD
)*(cParams
+1) ;
98 handle
= alloc_msihandle( MSIHANDLETYPE_RECORD
, sz
,
99 MSI_CloseRecord
, (void**) &rec
);
103 rec
->count
= cParams
;
108 unsigned int WINAPI
MsiRecordGetFieldCount( MSIHANDLE handle
)
112 TRACE("%ld\n", handle
);
114 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
117 ERR("Record not found!\n");
124 static BOOL
string2intW( LPCWSTR str
, int *out
)
129 if( *p
== '-' ) /* skip the minus sign */
133 if( (*p
< '0') || (*p
> '9') )
140 if( str
[0] == '-' ) /* check if it's negative */
147 int WINAPI
MsiRecordGetInteger( MSIHANDLE handle
, unsigned int iField
)
152 TRACE("%ld %d\n", handle
, iField
);
154 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
156 return MSI_NULL_INTEGER
;
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 UINT WINAPI
MsiRecordClearData( MSIHANDLE handle
)
181 TRACE("%ld\n", handle
);
183 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
185 return ERROR_INVALID_HANDLE
;
187 for( i
=0; i
<=rec
->count
; i
++)
189 MSI_FreeField( &rec
->fields
[i
] );
190 rec
->fields
[i
].type
= MSIFIELD_NULL
;
191 rec
->fields
[i
].u
.iVal
= 0;
194 return ERROR_SUCCESS
;
197 UINT WINAPI
MsiRecordSetInteger( MSIHANDLE handle
, unsigned int iField
, int iVal
)
201 TRACE("%ld %u %d\n", handle
,iField
, iVal
);
203 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
205 return ERROR_INVALID_HANDLE
;
207 if( iField
<= rec
->count
)
209 MSI_FreeField( &rec
->fields
[iField
] );
210 rec
->fields
[iField
].type
= MSIFIELD_INT
;
211 rec
->fields
[iField
].u
.iVal
= iVal
;
214 return ERROR_SUCCESS
;
217 BOOL WINAPI
MsiRecordIsNull( MSIHANDLE handle
, unsigned int iField
)
222 TRACE("%ld %d\n", handle
,iField
);
224 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
226 return ERROR_INVALID_HANDLE
;
228 r
= ( iField
> rec
->count
) ||
229 ( rec
->fields
[iField
].type
== MSIFIELD_NULL
);
234 UINT WINAPI
MsiRecordGetStringA(MSIHANDLE handle
, unsigned int iField
,
235 LPSTR szValue
, DWORD
*pcchValue
)
241 TRACE("%ld %d %p %p\n", handle
, iField
, szValue
, pcchValue
);
243 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
245 return ERROR_INVALID_HANDLE
;
247 if( iField
> rec
->count
)
248 return ERROR_INVALID_PARAMETER
;
251 switch( rec
->fields
[iField
].type
)
254 wsprintfA(buffer
, "%d", rec
->fields
[iField
].u
.iVal
);
255 len
= lstrlenA( buffer
);
256 lstrcpynA(szValue
, buffer
, *pcchValue
);
259 len
= WideCharToMultiByte( CP_ACP
, 0, rec
->fields
[iField
].u
.szwVal
, -1,
260 NULL
, 0 , NULL
, NULL
);
261 WideCharToMultiByte( CP_ACP
, 0, rec
->fields
[iField
].u
.szwVal
, -1,
262 szValue
, *pcchValue
, NULL
, NULL
);
269 ret
= ERROR_INVALID_PARAMETER
;
273 if( *pcchValue
< len
)
274 ret
= ERROR_MORE_DATA
;
280 const WCHAR
*MSI_RecordGetString( MSIHANDLE handle
, unsigned int iField
)
284 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
288 if( iField
> rec
->count
)
291 if( rec
->fields
[iField
].type
!= MSIFIELD_WSTR
)
294 return rec
->fields
[iField
].u
.szwVal
;
297 UINT WINAPI
MsiRecordGetStringW(MSIHANDLE handle
, unsigned int iField
,
298 LPWSTR szValue
, DWORD
*pcchValue
)
303 static const WCHAR szFormat
[] = { '%','d',0 };
305 TRACE("%ld %d %p %p\n", handle
, iField
, szValue
, pcchValue
);
307 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
309 return ERROR_INVALID_HANDLE
;
311 if( iField
> rec
->count
)
312 return ERROR_INVALID_PARAMETER
;
315 switch( rec
->fields
[iField
].type
)
318 wsprintfW(buffer
, szFormat
, rec
->fields
[iField
].u
.iVal
);
319 len
= lstrlenW( buffer
);
320 lstrcpynW(szValue
, buffer
, *pcchValue
);
323 len
= lstrlenW( rec
->fields
[iField
].u
.szwVal
);
324 lstrcpynW(szValue
, rec
->fields
[iField
].u
.szwVal
, *pcchValue
);
334 if( *pcchValue
< len
)
335 ret
= ERROR_MORE_DATA
;
341 UINT WINAPI
MsiRecordDataSize(MSIHANDLE hRecord
, unsigned int iField
)
343 FIXME("%ld %d\n", hRecord
, iField
);
347 UINT WINAPI
MsiRecordSetStringA( MSIHANDLE handle
, unsigned int iField
, LPCSTR szValue
)
353 TRACE("%ld %d %s\n", handle
, iField
, debugstr_a(szValue
));
355 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
357 return ERROR_INVALID_HANDLE
;
359 if( iField
> rec
->count
)
360 return ERROR_INVALID_FIELD
;
362 len
= MultiByteToWideChar( CP_ACP
, 0, szValue
, -1, NULL
, 0 );
363 str
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof(WCHAR
) );
364 MultiByteToWideChar( CP_ACP
, 0, szValue
, -1, str
, len
);
365 MSI_FreeField( &rec
->fields
[iField
] );
366 rec
->fields
[iField
].type
= MSIFIELD_WSTR
;
367 rec
->fields
[iField
].u
.szwVal
= str
;
372 UINT WINAPI
MsiRecordSetStringW( MSIHANDLE handle
, unsigned int iField
, LPCWSTR szValue
)
377 TRACE("%ld %d %s\n", handle
, iField
, debugstr_w(szValue
));
379 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
381 return ERROR_INVALID_HANDLE
;
383 if( iField
> rec
->count
)
384 return ERROR_INVALID_FIELD
;
386 str
= HeapAlloc( GetProcessHeap(), 0, (lstrlenW(szValue
) + 1)*sizeof (WCHAR
));
387 lstrcpyW( str
, szValue
);
389 MSI_FreeField( &rec
->fields
[iField
] );
390 rec
->fields
[iField
].type
= MSIFIELD_WSTR
;
391 rec
->fields
[iField
].u
.szwVal
= str
;
396 UINT WINAPI
MsiFormatRecordA(MSIHANDLE hInstall
, MSIHANDLE hRecord
, LPSTR szResult
, DWORD
*sz
)
398 FIXME("%ld %ld %p %p\n", hInstall
, hRecord
, szResult
, sz
);
399 return ERROR_CALL_NOT_IMPLEMENTED
;
402 UINT WINAPI
MsiFormatRecordW(MSIHANDLE hInstall
, MSIHANDLE hRecord
, LPWSTR szResult
, DWORD
*sz
)
404 FIXME("%ld %ld %p %p\n", hInstall
, hRecord
, szResult
, sz
);
405 return ERROR_CALL_NOT_IMPLEMENTED
;
408 UINT WINAPI
MsiRecordSetStreamA(MSIHANDLE hRecord
, unsigned int iField
, LPCSTR szFilename
)
410 FIXME("%ld %d %s\n", hRecord
, iField
, debugstr_a(szFilename
));
411 return ERROR_CALL_NOT_IMPLEMENTED
;
414 UINT WINAPI
MsiRecordSetStreamW(MSIHANDLE hRecord
, unsigned int iField
, LPCWSTR szFilename
)
416 FIXME("%ld %d %s\n", hRecord
, iField
, debugstr_w(szFilename
));
417 return ERROR_CALL_NOT_IMPLEMENTED
;
420 UINT WINAPI
MsiRecordReadStream(MSIHANDLE handle
, unsigned int iField
, char *buf
, DWORD
*sz
)
427 TRACE("%ld %d %p %p\n", handle
, iField
, buf
, sz
);
429 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
431 return ERROR_INVALID_HANDLE
;
433 if( iField
> rec
->count
)
434 return ERROR_INVALID_FIELD
;
436 if( rec
->fields
[iField
].type
!= MSIFIELD_STREAM
)
437 return ERROR_INVALID_FIELD
;
439 stm
= rec
->fields
[iField
].u
.stream
;
441 return ERROR_INVALID_FIELD
;
443 /* if there's no buffer pointer, calculate the length to the end */
447 ULARGE_INTEGER end
, cur
;
449 ofs
.QuadPart
= cur
.QuadPart
= 0;
451 r
= IStream_Seek( stm
, ofs
, STREAM_SEEK_SET
, &cur
);
452 IStream_Seek( stm
, ofs
, STREAM_SEEK_END
, &end
);
453 ofs
.QuadPart
= cur
.QuadPart
;
454 IStream_Seek( stm
, ofs
, STREAM_SEEK_SET
, &cur
);
455 *sz
= end
.QuadPart
- cur
.QuadPart
;
457 return ERROR_SUCCESS
;
462 r
= IStream_Read( stm
, buf
, *sz
, &count
);
464 return ERROR_FUNCTION_FAILED
;
468 return ERROR_SUCCESS
;
471 UINT WINAPI
MSI_RecordSetIStream( MSIHANDLE handle
, unsigned int iField
, IStream
*stm
)
475 TRACE("%ld %d %p\n", handle
, iField
, stm
);
477 rec
= msihandle2msiinfo( handle
, MSIHANDLETYPE_RECORD
);
479 return ERROR_INVALID_HANDLE
;
481 if( iField
> rec
->count
)
482 return ERROR_INVALID_FIELD
;
484 MSI_FreeField( &rec
->fields
[iField
] );
486 rec
->fields
[iField
].type
= MSIFIELD_STREAM
;
487 rec
->fields
[iField
].u
.stream
= stm
;
488 IStream_AddRef( stm
);
490 return ERROR_SUCCESS
;