Commit 921be0a8 authored by Mike McCormack's avatar Mike McCormack Committed by Alexandre Julliard

Implement MsiRecordSetStreamA/W and add tests for records containing

streams.
parent dd8fccfe
......@@ -32,6 +32,7 @@
#include "msipriv.h"
#include "objidl.h"
#include "winnls.h"
#include "ole2.h"
#include "query.h"
......@@ -531,16 +532,133 @@ UINT WINAPI MsiFormatRecordW(MSIHANDLE hInstall, MSIHANDLE hRecord, LPWSTR szRes
return ERROR_CALL_NOT_IMPLEMENTED;
}
/* read the data in a file into an IStream */
UINT RECORD_StreamFromFile(LPCWSTR szFile, IStream **pstm)
{
DWORD sz, szHighWord = 0, read;
HANDLE handle;
HGLOBAL hGlob = 0;
HRESULT hr;
ULARGE_INTEGER ulSize;
TRACE("reading %s\n", debugstr_w(szFile));
/* read the file into memory */
handle = CreateFileW(szFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if( handle == INVALID_HANDLE_VALUE )
return GetLastError();
sz = GetFileSize(handle, &szHighWord);
if( sz != INVALID_FILE_SIZE && szHighWord == 0 )
{
hGlob = GlobalAlloc(GMEM_FIXED, sz);
if( hGlob )
{
BOOL r = ReadFile(handle, hGlob, sz, &read, NULL);
if( !r )
{
GlobalFree(hGlob);
hGlob = 0;
}
}
}
CloseHandle(handle);
if( !hGlob )
return ERROR_FUNCTION_FAILED;
/* make a stream out of it, and set the correct file size */
hr = CreateStreamOnHGlobal(hGlob, TRUE, pstm);
if( FAILED( hr ) )
{
GlobalFree(hGlob);
return ERROR_FUNCTION_FAILED;
}
/* set the correct size - CreateStreamOnHGlobal screws it up */
ulSize.QuadPart = sz;
IStream_SetSize(*pstm, ulSize);
TRACE("read %s, %ld bytes into IStream %p\n", debugstr_w(szFile), sz, *pstm);
return ERROR_SUCCESS;
}
UINT MSI_RecordSetStreamW(MSIRECORD *rec, unsigned int iField, LPCWSTR szFilename)
{
IStream *stm = NULL;
HRESULT r;
if( (iField == 0) || (iField > rec->count) )
return ERROR_INVALID_PARAMETER;
/* no filename means we should seek back to the start of the stream */
if( !szFilename )
{
LARGE_INTEGER ofs;
ULARGE_INTEGER cur;
if( rec->fields[iField].type != MSIFIELD_STREAM )
return ERROR_INVALID_FIELD;
stm = rec->fields[iField].u.stream;
if( !stm )
return ERROR_INVALID_FIELD;
ofs.QuadPart = 0;
r = IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );
if( FAILED( r ) )
return ERROR_FUNCTION_FAILED;
}
else
{
/* read the file into a stream and save the stream in the record */
r = RECORD_StreamFromFile(szFilename, &stm);
if( r != ERROR_SUCCESS )
return r;
/* if all's good, store it in the record */
MSI_FreeField( &rec->fields[iField] );
rec->fields[iField].type = MSIFIELD_STREAM;
rec->fields[iField].u.stream = stm;
}
return ERROR_SUCCESS;
}
UINT WINAPI MsiRecordSetStreamA(MSIHANDLE hRecord, unsigned int iField, LPCSTR szFilename)
{
FIXME("%ld %d %s\n", hRecord, iField, debugstr_a(szFilename));
return ERROR_CALL_NOT_IMPLEMENTED;
LPWSTR wstr = NULL;
UINT ret, len;
TRACE("%ld %d %s\n", hRecord, iField, debugstr_a(szFilename));
if( szFilename )
{
len = MultiByteToWideChar(CP_ACP,0,szFilename,-1,NULL,0);
wstr = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR));
MultiByteToWideChar(CP_ACP,0,szFilename,-1,wstr,len);
}
ret = MsiRecordSetStreamW(hRecord, iField, wstr);
HeapFree(GetProcessHeap(),0,wstr);
return ret;
}
UINT WINAPI MsiRecordSetStreamW(MSIHANDLE hRecord, unsigned int iField, LPCWSTR szFilename)
UINT WINAPI MsiRecordSetStreamW(MSIHANDLE handle, unsigned int iField, LPCWSTR szFilename)
{
FIXME("%ld %d %s\n", hRecord, iField, debugstr_w(szFilename));
return ERROR_CALL_NOT_IMPLEMENTED;
MSIRECORD *rec;
UINT ret;
TRACE("%ld %d %s\n", handle, iField, debugstr_w(szFilename));
rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
if( !rec )
return ERROR_INVALID_HANDLE;
msiobj_lock( &rec->hdr );
ret = MSI_RecordSetStreamW( rec, iField, szFilename );
msiobj_unlock( &rec->hdr );
msiobj_release( &rec->hdr );
return ret;
}
UINT MSI_RecordReadStream(MSIRECORD *rec, unsigned int iField, char *buf, DWORD *sz)
......@@ -551,18 +669,18 @@ UINT MSI_RecordReadStream(MSIRECORD *rec, unsigned int iField, char *buf, DWORD
TRACE("%p %d %p %p\n", rec, iField, buf, sz);
if( iField > rec->count )
return ERROR_INVALID_FIELD;
if( !sz )
return ERROR_INVALID_PARAMETER;
if( iField > rec->count)
return ERROR_INVALID_PARAMETER;
if( rec->fields[iField].type != MSIFIELD_STREAM )
{
*sz = 0;
return ERROR_INVALID_FIELD;
}
return ERROR_INVALID_DATATYPE;
stm = rec->fields[iField].u.stream;
if( !stm )
return ERROR_INVALID_FIELD;
return ERROR_INVALID_PARAMETER;
/* if there's no buffer pointer, calculate the length to the end */
if( !buf )
......
......@@ -24,6 +24,27 @@
#include "wine/test.h"
static BOOL create_temp_file(char *name)
{
UINT r;
unsigned char buffer[26], i;
DWORD sz;
HANDLE handle;
r = GetTempFileName(".", "msitest",0,name);
if(!r)
return r;
handle = CreateFile(name, GENERIC_READ|GENERIC_WRITE,
0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if(handle==INVALID_HANDLE_VALUE)
return 0;
for(i=0; i<26; i++)
buffer[i]=i+'a';
r = WriteFile(handle,buffer,sizeof buffer,&sz,NULL);
CloseHandle(handle);
return r;
}
void test_msirecord(void)
{
DWORD r, sz;
......@@ -31,6 +52,7 @@ void test_msirecord(void)
MSIHANDLE h;
char buf[10];
const char str[] = "hello";
char filename[MAX_PATH];
/* check behaviour with an invalid record */
r = MsiRecordGetFieldCount(0);
......@@ -88,10 +110,8 @@ void test_msirecord(void)
r = MsiRecordSetInteger(h, 0, 1);
ok(r == ERROR_SUCCESS, "Failed to set integer at 0 to 1\n");
r = MsiRecordSetInteger(h, 1, 1);
/*printf("r = %d\n",r); */
ok(r == ERROR_INVALID_PARAMETER, "set integer at 1\n");
r = MsiRecordSetInteger(h, -1, 0);
/*printf("r = %d\n",r); */
ok(r == ERROR_INVALID_PARAMETER, "set integer at -1\n");
r = MsiRecordIsNull(h,0);
ok(r==0, "new record is null after setting an integer\n");
......@@ -185,9 +205,75 @@ void test_msirecord(void)
ok(r == ERROR_SUCCESS, "failed to get string from integer\n");
ok(0==strcmp(buf,"-32"), "failed to get string from integer\n");
/* same record, now try streams */
r = MsiRecordSetStream(h, 0, NULL);
ok(r == ERROR_INVALID_PARAMETER, "set NULL stream\n");
sz = sizeof buf;
r = MsiRecordReadStream(h, 0, buf, &sz);
ok(r == ERROR_INVALID_DATATYPE, "read non-stream type\n");
ok(sz == sizeof buf, "set sz\n");
/* same record, now close it */
r = MsiCloseHandle(h);
ok(r == ERROR_SUCCESS, "Failed to close handle\n");
/* now try streams in a new record - need to create a file to play with */
r = create_temp_file(filename);
if(!r)
return;
/* streams can't be inserted in field 0 for some reason */
h = MsiCreateRecord(2);
ok(h, "couldn't create a two field record\n");
r = MsiRecordSetStream(h, 0, filename);
ok(r == ERROR_INVALID_PARAMETER, "added stream to field 0\n");
r = MsiRecordSetStream(h, 1, filename);
ok(r == ERROR_SUCCESS, "failed to add stream to record\n");
r = MsiRecordReadStream(h, 1, buf, NULL);
ok(r == ERROR_INVALID_PARAMETER, "should return error\n");
ok(DeleteFile(filename), "failed to delete stream temp file\n");
r = MsiRecordReadStream(h, 1, NULL, NULL);
ok(r == ERROR_INVALID_PARAMETER, "should return error\n");
sz = sizeof buf;
r = MsiRecordReadStream(h, 1, NULL, &sz);
ok(r == ERROR_SUCCESS, "failed to read stream\n");
ok(sz==26,"couldn't get size of stream");
sz = 0;
r = MsiRecordReadStream(h, 1, buf, &sz);
ok(r == ERROR_SUCCESS, "failed to read stream\n");
ok(sz==0,"short read");
sz = sizeof buf;
r = MsiRecordReadStream(h, 1, buf, &sz);
ok(r == ERROR_SUCCESS, "failed to read stream\n");
ok(sz==sizeof buf,"short read");
ok(!strncmp(buf,"abcdefghij",10), "read the wrong thing\n");
sz = sizeof buf;
r = MsiRecordReadStream(h, 1, buf, &sz);
ok(r == ERROR_SUCCESS, "failed to read stream\n");
ok(sz==sizeof buf,"short read");
ok(!strncmp(buf,"klmnopqrst",10), "read the wrong thing\n");
memset(buf,0,sizeof buf);
sz = sizeof buf;
r = MsiRecordReadStream(h, 1, buf, &sz);
ok(r == ERROR_SUCCESS, "failed to read stream\n");
ok(sz==6,"short read");
ok(!strcmp(buf,"uvwxyz"), "read the wrong thing\n");
memset(buf,0,sizeof buf);
sz = sizeof buf;
r = MsiRecordReadStream(h, 1, buf, &sz);
ok(r == ERROR_SUCCESS, "failed to read stream\n");
ok(sz==0,"size non-zero at end of stream\n");
ok(buf[0]==0, "read something at end of the stream\n");
r = MsiRecordSetStream(h, 1, NULL);
ok(r == ERROR_SUCCESS, "failed to reset stream\n");
sz = 0;
r = MsiRecordReadStream(h, 1, NULL, &sz);
ok(r == ERROR_SUCCESS, "bytes left wrong after reset\n");
ok(sz==26,"couldn't get size of stream\n");
/* now close the stream record */
r = MsiCloseHandle(h);
ok(r == ERROR_SUCCESS, "Failed to close handle\n");
}
START_TEST(record)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment