Implemented ProcessComponents.
[wine/testsucceed.git] / dlls / msi / msi.c
blob906fa87a76033ab502cf02d789cbff3591508c50
1 /*
2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2002,2003 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
21 #define NONAMELESSUNION
23 #include <stdarg.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winreg.h"
28 #include "winnls.h"
29 #include "shlwapi.h"
30 #include "wine/debug.h"
31 #include "msi.h"
32 #include "msiquery.h"
33 #include "msipriv.h"
34 #include "objidl.h"
35 #include "wincrypt.h"
36 #include "wine/unicode.h"
37 #include "objbase.h"
39 #include "initguid.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(msi);
44 * The MSVC headers define the MSIDBOPEN_* macros cast to LPCTSTR,
45 * which is a problem because LPCTSTR isn't defined when compiling wine.
46 * To work around this problem, we need to define LPCTSTR as LPCWSTR here,
47 * and make sure to only use it in W functions.
49 #define LPCTSTR LPCWSTR
51 DEFINE_GUID( CLSID_MsiDatabase, 0x000c1084, 0x0000, 0x0000, 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46);
53 static const WCHAR szInstaller[] = {
54 'S','o','f','t','w','a','r','e','\\',
55 'M','i','c','r','o','s','o','f','t','\\',
56 'W','i','n','d','o','w','s','\\',
57 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
58 'I','n','s','t','a','l','l','e','r',0 };
60 static const WCHAR szFeatures[] = {
61 'F','e','a','t','u','r','e','s',0 };
62 static const WCHAR szComponents[] = {
63 'C','o','m','p','o','n','e','n','t','s',0 };
65 /* the UI level */
66 INSTALLUILEVEL gUILevel;
67 HWND gUIhwnd;
68 INSTALLUI_HANDLERA gUIHandler;
69 DWORD gUIFilter;
70 LPVOID gUIContext;
73 * .MSI file format
75 * A .msi file is a structured storage file.
76 * It should contain a number of streams.
79 BOOL unsquash_guid(LPCWSTR in, LPWSTR out)
81 DWORD i,n=0;
83 out[n++]='{';
84 for(i=0; i<8; i++)
85 out[n++] = in[7-i];
86 out[n++]='-';
87 for(i=0; i<4; i++)
88 out[n++] = in[11-i];
89 out[n++]='-';
90 for(i=0; i<4; i++)
91 out[n++] = in[15-i];
92 out[n++]='-';
93 for(i=0; i<2; i++)
95 out[n++] = in[17+i*2];
96 out[n++] = in[16+i*2];
98 out[n++]='-';
99 for( ; i<8; i++)
101 out[n++] = in[17+i*2];
102 out[n++] = in[16+i*2];
104 out[n++]='}';
105 out[n]=0;
106 return TRUE;
109 BOOL squash_guid(LPCWSTR in, LPWSTR out)
111 DWORD i,n=0;
113 if(in[n++] != '{')
114 return FALSE;
115 for(i=0; i<8; i++)
116 out[7-i] = in[n++];
117 if(in[n++] != '-')
118 return FALSE;
119 for(i=0; i<4; i++)
120 out[11-i] = in[n++];
121 if(in[n++] != '-')
122 return FALSE;
123 for(i=0; i<4; i++)
124 out[15-i] = in[n++];
125 if(in[n++] != '-')
126 return FALSE;
127 for(i=0; i<2; i++)
129 out[17+i*2] = in[n++];
130 out[16+i*2] = in[n++];
132 if(in[n++] != '-')
133 return FALSE;
134 for( ; i<8; i++)
136 out[17+i*2] = in[n++];
137 out[16+i*2] = in[n++];
139 out[32]=0;
140 if(in[n++] != '}')
141 return FALSE;
142 if(in[n])
143 return FALSE;
144 return TRUE;
147 VOID MSI_CloseDatabase( VOID *arg )
149 MSIDATABASE *db = (MSIDATABASE *) arg;
151 free_cached_tables( db );
152 IStorage_Release( db->storage );
155 UINT WINAPI MsiOpenDatabaseA(LPCSTR szDBPath, LPCSTR szPersist, MSIHANDLE *phDB)
157 HRESULT r = ERROR_FUNCTION_FAILED;
158 LPWSTR szwDBPath = NULL, szwPersist = NULL;
159 UINT len;
161 TRACE("%s %s %p\n", debugstr_a(szDBPath), debugstr_a(szPersist), phDB);
163 if( szDBPath )
165 len = MultiByteToWideChar( CP_ACP, 0, szDBPath, -1, NULL, 0 );
166 szwDBPath = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
167 if( !szwDBPath )
168 goto end;
169 MultiByteToWideChar( CP_ACP, 0, szDBPath, -1, szwDBPath, len );
172 if( HIWORD(szPersist) )
174 len = MultiByteToWideChar( CP_ACP, 0, szPersist, -1, NULL, 0 );
175 szwPersist = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
176 if( !szwPersist )
177 goto end;
178 MultiByteToWideChar( CP_ACP, 0, szPersist, -1, szwPersist, len );
180 else
181 szwPersist = (LPWSTR) szPersist;
183 r = MsiOpenDatabaseW( szwDBPath, szwPersist, phDB );
185 end:
186 if( szwPersist )
187 HeapFree( GetProcessHeap(), 0, szwPersist );
188 if( szwDBPath )
189 HeapFree( GetProcessHeap(), 0, szwDBPath );
191 return r;
194 UINT WINAPI MsiOpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIHANDLE *phDB)
196 IStorage *stg = NULL;
197 HRESULT r;
198 MSIHANDLE handle;
199 MSIDATABASE *db;
200 UINT ret;
201 LPWSTR szMode;
202 STATSTG stat;
204 TRACE("%s %s %p\n",debugstr_w(szDBPath),debugstr_w(szPersist), phDB);
206 if( !phDB )
207 return ERROR_INVALID_PARAMETER;
209 szMode = (LPWSTR) szPersist;
210 if( HIWORD( szPersist ) )
212 /* UINT len = lstrlenW( szPerist ) + 1; */
213 FIXME("don't support persist files yet\b");
214 return ERROR_INVALID_PARAMETER;
215 /* szMode = HeapAlloc( GetProcessHeap(), 0, len * sizeof (DWORD) ); */
217 else if( szPersist == MSIDBOPEN_READONLY )
219 r = StgOpenStorage( szDBPath, NULL,
220 STGM_DIRECT|STGM_READ|STGM_SHARE_DENY_WRITE, NULL, 0, &stg);
222 else if( szPersist == MSIDBOPEN_CREATE )
224 r = StgCreateDocfile( szDBPath,
225 STGM_DIRECT|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, 0, &stg);
226 if( r == ERROR_SUCCESS )
228 IStorage_SetClass( stg, &CLSID_MsiDatabase );
229 r = init_string_table( stg );
232 else if( szPersist == MSIDBOPEN_TRANSACT )
234 r = StgOpenStorage( szDBPath, NULL,
235 STGM_DIRECT|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, NULL, 0, &stg);
237 else
239 ERR("unknown flag %p\n",szPersist);
240 return ERROR_INVALID_PARAMETER;
243 if( FAILED( r ) )
245 FIXME("open failed r = %08lx!\n",r);
246 return ERROR_FUNCTION_FAILED;
249 r = IStorage_Stat( stg, &stat, STATFLAG_NONAME );
250 if( FAILED( r ) )
252 FIXME("Failed to stat storage\n");
253 ret = ERROR_FUNCTION_FAILED;
254 goto end;
257 if( memcmp( &stat.clsid, &CLSID_MsiDatabase, sizeof (GUID) ) )
259 ERR("storage GUID is not a MSI database GUID %s\n",
260 debugstr_guid(&stat.clsid) );
261 ret = ERROR_FUNCTION_FAILED;
262 goto end;
266 handle = alloc_msihandle( MSIHANDLETYPE_DATABASE, sizeof (MSIDATABASE),
267 MSI_CloseDatabase, (void**) &db );
268 if( !handle )
270 FIXME("Failed to allocate a handle\n");
271 ret = ERROR_FUNCTION_FAILED;
272 goto end;
275 if( TRACE_ON( msi ) )
276 enum_stream_names( stg );
278 db->storage = stg;
279 db->mode = szMode;
280 /* db->strings = NULL;
281 db->first_table = NULL;
282 db->last_table = NULL; */
284 ret = load_string_table( db );
285 if( ret != ERROR_SUCCESS )
286 goto end;
288 *phDB = handle;
290 IStorage_AddRef( stg );
291 end:
292 if( stg )
293 IStorage_Release( stg );
295 return ret;
298 UINT WINAPI MsiOpenProductA(LPCSTR szProduct, MSIHANDLE *phProduct)
300 UINT len, ret;
301 LPWSTR szwProd = NULL;
303 TRACE("%s %p\n",debugstr_a(szProduct), phProduct);
305 if( szProduct )
307 len = MultiByteToWideChar( CP_ACP, 0, szProduct, -1, NULL, 0 );
308 szwProd = HeapAlloc( GetProcessHeap(), 0, len * sizeof (WCHAR) );
309 if( szwProd )
310 MultiByteToWideChar( CP_ACP, 0, szProduct, -1, szwProd, len );
313 ret = MsiOpenProductW( szwProd, phProduct );
315 if( szwProd )
316 HeapFree( GetProcessHeap(), 0, szwProd );
318 return ret;
321 UINT WINAPI MsiOpenProductW(LPCWSTR szProduct, MSIHANDLE *phProduct)
323 static const WCHAR szKey[] = {
324 'S','o','f','t','w','a','r','e','\\',
325 'M','i','c','r','o','s','o','f','t','\\',
326 'W','i','n','d','o','w','s','\\',
327 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
328 'U','n','i','n','s','t','a','l','l',0 };
329 static const WCHAR szLocalPackage[] = {
330 'L','o','c','a','l','P','a','c','k','a','g','e', 0
332 LPWSTR path = NULL;
333 UINT r;
334 HKEY hKeyProduct = NULL, hKeyUninstall = NULL;
335 DWORD count, type;
337 TRACE("%s %p\n",debugstr_w(szProduct), phProduct);
339 r = RegOpenKeyW( HKEY_LOCAL_MACHINE, szKey, &hKeyUninstall );
340 if( r != ERROR_SUCCESS )
341 return ERROR_UNKNOWN_PRODUCT;
343 r = RegOpenKeyW( hKeyUninstall, szProduct, &hKeyProduct );
344 if( r != ERROR_SUCCESS )
346 r = ERROR_UNKNOWN_PRODUCT;
347 goto end;
350 /* find the size of the path */
351 type = count = 0;
352 r = RegQueryValueExW( hKeyProduct, szLocalPackage,
353 NULL, &type, NULL, &count );
354 if( r != ERROR_SUCCESS )
356 r = ERROR_UNKNOWN_PRODUCT;
357 goto end;
360 /* now alloc and fetch the path of the database to open */
361 path = HeapAlloc( GetProcessHeap(), 0, count );
362 if( !path )
363 goto end;
365 r = RegQueryValueExW( hKeyProduct, szLocalPackage,
366 NULL, &type, (LPBYTE) path, &count );
367 if( r != ERROR_SUCCESS )
369 r = ERROR_UNKNOWN_PRODUCT;
370 goto end;
373 r = MsiOpenPackageW( path, phProduct );
375 end:
376 if( path )
377 HeapFree( GetProcessHeap(), 0, path );
378 if( hKeyProduct )
379 RegCloseKey( hKeyProduct );
380 RegCloseKey( hKeyUninstall );
382 return r;
385 UINT WINAPI MsiAdvertiseProductA(LPCSTR szPackagePath, LPCSTR szScriptfilePath, LPCSTR szTransforms, LANGID lgidLanguage)
387 FIXME("%s %s %s 0x%08x\n",debugstr_a(szPackagePath), debugstr_a(szScriptfilePath), debugstr_a(szTransforms), lgidLanguage);
388 return ERROR_CALL_NOT_IMPLEMENTED;
391 UINT WINAPI MsiAdvertiseProductW(LPCWSTR szPackagePath, LPCWSTR szScriptfilePath, LPCWSTR szTransforms, LANGID lgidLanguage)
393 FIXME("%s %s %s 0x%08x\n",debugstr_w(szPackagePath), debugstr_w(szScriptfilePath), debugstr_w(szTransforms), lgidLanguage);
394 return ERROR_CALL_NOT_IMPLEMENTED;
397 UINT WINAPI MsiAdvertiseProductExA(LPCSTR szPackagePath, LPCSTR szScriptfilePath, LPCSTR szTransforms, LANGID lgidLanguage, DWORD dwPlatform, DWORD dwOptions)
399 FIXME("%s %s %s 0x%08x 0x%08lx 0x%08lx\n",
400 debugstr_a(szPackagePath), debugstr_a(szScriptfilePath), debugstr_a(szTransforms), lgidLanguage, dwPlatform, dwOptions);
401 return ERROR_CALL_NOT_IMPLEMENTED;
404 UINT WINAPI MsiAdvertiseProductExW( LPCWSTR szPackagePath, LPCWSTR szScriptfilePath, LPCWSTR szTransforms, LANGID lgidLanguage, DWORD dwPlatform, DWORD dwOptions)
406 FIXME("%s %s %s 0x%08x 0x%08lx 0x%08lx\n",
407 debugstr_w(szPackagePath), debugstr_w(szScriptfilePath), debugstr_w(szTransforms), lgidLanguage, dwPlatform, dwOptions);
408 return ERROR_CALL_NOT_IMPLEMENTED;
411 UINT WINAPI MsiInstallProductA(LPCSTR szPackagePath, LPCSTR szCommandLine)
413 LPWSTR szwPath = NULL, szwCommand = NULL;
414 UINT r = ERROR_FUNCTION_FAILED; /* FIXME: check return code */
416 TRACE("%s %s\n",debugstr_a(szPackagePath), debugstr_a(szCommandLine));
418 if( szPackagePath )
420 UINT len = MultiByteToWideChar( CP_ACP, 0, szPackagePath, -1, NULL, 0 );
421 szwPath = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
422 if( !szwPath )
423 goto end;
424 MultiByteToWideChar( CP_ACP, 0, szPackagePath, -1, szwPath, len );
427 if( szCommandLine )
429 UINT len = MultiByteToWideChar( CP_ACP, 0, szCommandLine, -1, NULL, 0 );
430 szwCommand = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
431 if( !szwCommand )
432 goto end;
433 MultiByteToWideChar( CP_ACP, 0, szCommandLine, -1, szwCommand, len );
436 r = MsiInstallProductW( szwPath, szwCommand );
438 end:
439 if( szwPath )
440 HeapFree( GetProcessHeap(), 0, szwPath );
442 if( szwCommand )
443 HeapFree( GetProcessHeap(), 0, szwCommand );
445 return r;
448 UINT WINAPI MsiInstallProductW(LPCWSTR szPackagePath, LPCWSTR szCommandLine)
450 MSIHANDLE packagehandle;
451 UINT rc = ERROR_SUCCESS;
453 FIXME("%s %s\n",debugstr_w(szPackagePath), debugstr_w(szCommandLine));
455 rc = MsiVerifyPackageW(szPackagePath);
456 if (rc != ERROR_SUCCESS)
457 return rc;
459 rc = MsiOpenPackageW(szPackagePath,&packagehandle);
460 if (rc != ERROR_SUCCESS)
461 return rc;
463 ACTION_DoTopLevelINSTALL(packagehandle, szPackagePath, szCommandLine);
465 MsiCloseHandle(packagehandle);
466 return rc;
469 UINT WINAPI MsiConfigureProductA(LPCSTR szProduct, int iInstallLevel, INSTALLSTATE eInstallState)
471 LPWSTR szwProduct = NULL;
472 UINT hr = ERROR_SUCCESS;
474 FIXME("%s %d %d\n",debugstr_a(szProduct), iInstallLevel, eInstallState);
476 if( szProduct )
478 UINT len = MultiByteToWideChar( CP_ACP, 0, szProduct, -1, NULL, 0 );
479 szwProduct = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
480 if( !szwProduct )
481 goto end;
482 MultiByteToWideChar( CP_ACP, 0, szProduct, -1, szwProduct, len );
485 hr = MsiConfigureProductW( szwProduct, iInstallLevel, eInstallState );
487 end:
488 if( szwProduct )
489 HeapFree( GetProcessHeap(), 0, szwProduct );
491 return hr;
494 UINT WINAPI MsiConfigureProductW(LPCWSTR szProduct, int iInstallLevel, INSTALLSTATE eInstallState)
496 FIXME("%s %d %d\n",debugstr_w(szProduct), iInstallLevel, eInstallState);
497 return ERROR_CALL_NOT_IMPLEMENTED;
500 UINT WINAPI MsiGetProductCodeA(LPCSTR szComponent, LPSTR szBuffer)
502 LPWSTR szwComponent = NULL, szwBuffer = NULL;
503 UINT hr = ERROR_INSTALL_FAILURE;
505 FIXME("%s %s\n",debugstr_a(szComponent), debugstr_a(szBuffer));
507 if( szComponent )
509 UINT len = MultiByteToWideChar( CP_ACP, 0, szComponent, -1, NULL, 0 );
510 szwComponent = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
511 if( !szwComponent )
512 goto end;
513 MultiByteToWideChar( CP_ACP, 0, szComponent, -1, szwComponent, len );
514 } else {
515 return ERROR_INVALID_PARAMETER;
519 szwBuffer = HeapAlloc( GetProcessHeap(), 0, GUID_SIZE * sizeof(WCHAR) );
520 if( !szwBuffer )
521 goto end;
524 hr = MsiGetProductCodeW( szwComponent, szwBuffer );
526 if( ERROR_SUCCESS == hr )
528 WideCharToMultiByte(CP_ACP, 0, szwBuffer, -1, szBuffer, GUID_SIZE, NULL, NULL);
531 end:
532 if( szwComponent )
533 HeapFree( GetProcessHeap(), 0, szwComponent );
534 if( szwBuffer )
535 HeapFree( GetProcessHeap(), 0, szwBuffer );
537 return hr;
540 UINT WINAPI MsiGetProductCodeW(LPCWSTR szComponent, LPWSTR szBuffer)
542 FIXME("%s %s\n",debugstr_w(szComponent), debugstr_w(szBuffer));
543 if (NULL == szComponent) {
544 return ERROR_INVALID_PARAMETER;
546 return ERROR_CALL_NOT_IMPLEMENTED;
552 UINT WINAPI MsiGetProductInfoA(LPCSTR szProduct, LPCSTR szAttribute, LPSTR szBuffer, DWORD *pcchValueBuf)
554 LPWSTR szwProduct = NULL, szwAttribute = NULL, szwBuffer = NULL;
555 UINT hr = ERROR_INSTALL_FAILURE;
557 FIXME("%s %s %p %p\n",debugstr_a(szProduct), debugstr_a(szAttribute), szBuffer, pcchValueBuf);
559 if (NULL != szBuffer && NULL == pcchValueBuf) {
560 return ERROR_INVALID_PARAMETER;
562 if( szProduct )
564 UINT len = MultiByteToWideChar( CP_ACP, 0, szProduct, -1, NULL, 0 );
565 szwProduct = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
566 if( !szwProduct )
567 goto end;
568 MultiByteToWideChar( CP_ACP, 0, szProduct, -1, szwProduct, len );
569 } else {
570 return ERROR_INVALID_PARAMETER;
573 if( szAttribute )
575 UINT len = MultiByteToWideChar( CP_ACP, 0, szAttribute, -1, NULL, 0 );
576 szwAttribute = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
577 if( !szwAttribute )
578 goto end;
579 MultiByteToWideChar( CP_ACP, 0, szAttribute, -1, szwAttribute, len );
580 } else {
581 return ERROR_INVALID_PARAMETER;
584 if( szBuffer )
586 szwBuffer = HeapAlloc( GetProcessHeap(), 0, (*pcchValueBuf) * sizeof(WCHAR) );
587 if( !szwBuffer )
588 goto end;
591 hr = MsiGetProductInfoW( szwProduct, szwAttribute, szwBuffer, pcchValueBuf );
593 if( ERROR_SUCCESS == hr )
595 WideCharToMultiByte(CP_ACP, 0, szwBuffer, -1, szBuffer, *pcchValueBuf, NULL, NULL);
598 end:
599 if( szwProduct )
600 HeapFree( GetProcessHeap(), 0, szwProduct );
601 if( szwAttribute )
602 HeapFree( GetProcessHeap(), 0, szwAttribute );
603 if( szwBuffer )
604 HeapFree( GetProcessHeap(), 0, szwBuffer );
606 return hr;
609 UINT WINAPI MsiGetProductInfoW(LPCWSTR szProduct, LPCWSTR szAttribute, LPWSTR szBuffer, DWORD *pcchValueBuf)
611 MSIHANDLE hProduct;
612 UINT hr;
614 FIXME("%s %s %p %p\n",debugstr_w(szProduct), debugstr_w(szAttribute), szBuffer, pcchValueBuf);
616 if (NULL != szBuffer && NULL == pcchValueBuf) {
617 return ERROR_INVALID_PARAMETER;
619 if (NULL == szProduct || NULL == szAttribute) {
620 return ERROR_INVALID_PARAMETER;
623 hr = MsiOpenProductW(szProduct, &hProduct);
624 if (ERROR_SUCCESS != hr) return hr;
626 hr = MsiGetPropertyW(hProduct, szAttribute, szBuffer, pcchValueBuf);
627 MsiCloseHandle(hProduct);
628 return hr;
631 UINT WINAPI MsiDatabaseImportA(LPCSTR szFolderPath, LPCSTR szFilename)
633 FIXME("%s %s\n",debugstr_a(szFolderPath), debugstr_a(szFilename));
634 return ERROR_CALL_NOT_IMPLEMENTED;
637 UINT WINAPI MsiDatabaseImportW(LPCWSTR szFolderPath, LPCWSTR szFilename)
639 FIXME("%s %s\n",debugstr_w(szFolderPath), debugstr_w(szFilename));
640 return ERROR_CALL_NOT_IMPLEMENTED;
643 UINT WINAPI MsiEnableLogA(DWORD dwLogMode, LPCSTR szLogFile, BOOL fAppend)
645 LPWSTR szwLogFile = NULL;
646 UINT hr = ERROR_INSTALL_FAILURE;
648 FIXME("%08lx %s %d\n", dwLogMode, debugstr_a(szLogFile), fAppend);
650 if( szLogFile )
652 UINT len = MultiByteToWideChar( CP_ACP, 0, szLogFile, -1, NULL, 0 );
653 szwLogFile = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
654 if( !szwLogFile )
655 goto end;
656 MultiByteToWideChar( CP_ACP, 0, szLogFile, -1, szwLogFile, len );
657 } else {
658 return ERROR_INVALID_PARAMETER;
661 hr = MsiEnableLogW( dwLogMode, szwLogFile, fAppend );
663 end:
664 if( szwLogFile )
665 HeapFree( GetProcessHeap(), 0, szwLogFile );
667 return hr;
670 UINT WINAPI MsiEnableLogW(DWORD dwLogMode, LPCWSTR szLogFile, BOOL fAppend)
672 FIXME("%08lx %s %d\n", dwLogMode, debugstr_w(szLogFile), fAppend);
673 return ERROR_SUCCESS;
674 /* return ERROR_CALL_NOT_IMPLEMENTED; */
677 INSTALLSTATE WINAPI MsiQueryProductStateA(LPCSTR szProduct)
679 FIXME("%s\n", debugstr_a(szProduct));
680 return INSTALLSTATE_UNKNOWN;
683 INSTALLSTATE WINAPI MsiQueryProductStateW(LPCWSTR szProduct)
685 FIXME("%s\n", debugstr_w(szProduct));
686 return INSTALLSTATE_UNKNOWN;
689 INSTALLUILEVEL WINAPI MsiSetInternalUI(INSTALLUILEVEL dwUILevel, HWND *phWnd)
691 INSTALLUILEVEL old = gUILevel;
692 HWND oldwnd = gUIhwnd;
693 TRACE("%08x %p\n", dwUILevel, phWnd);
695 gUILevel = dwUILevel;
696 if (phWnd)
698 gUIhwnd = *phWnd;
699 *phWnd = oldwnd;
701 return old;
704 INSTALLUI_HANDLERA WINAPI MsiSetExternalUIA(INSTALLUI_HANDLERA puiHandler,
705 DWORD dwMessageFilter, LPVOID pvContext)
707 INSTALLUI_HANDLERA prev = gUIHandler;
709 TRACE("(%p %lx %p)\n",puiHandler,dwMessageFilter,pvContext);
710 gUIHandler = puiHandler;
711 gUIFilter = dwMessageFilter;
712 gUIContext = pvContext;
714 return prev;
717 UINT WINAPI MsiLoadStringA(HINSTANCE hInstance, UINT uID, LPSTR lpBuffer, int nBufferMax, DWORD e)
719 /*FIXME("%08lx %08lx %08lx %08lx %08lx\n",a,b,c,d,e);*/
720 FIXME("%p %u %p %d %08lx\n",hInstance,uID,lpBuffer,nBufferMax,e);
721 return ERROR_CALL_NOT_IMPLEMENTED;
724 UINT WINAPI MsiLoadStringW(HINSTANCE hInstance, UINT uID, LPWSTR lpBuffer, int nBufferMax, DWORD e)
726 FIXME("%p %u %p %d %08lx\n",hInstance,uID,lpBuffer,nBufferMax,e);
728 int ret = LoadStringW(hInstance,uID,lpBuffer,nBufferMax);
729 FIXME("%s\n",debugstr_w(lpBuffer));
730 return ret;
732 return ERROR_CALL_NOT_IMPLEMENTED;
735 INSTALLSTATE WINAPI MsiLocateComponentA(LPCSTR szComponent, LPSTR lpPathBuf, DWORD *pcchBuf)
737 FIXME("%s %p %08lx\n", debugstr_a(szComponent), lpPathBuf, *pcchBuf);
738 return INSTALLSTATE_UNKNOWN;
741 INSTALLSTATE WINAPI MsiLocateComponentW(LPCWSTR szComponent, LPSTR lpPathBuf, DWORD *pcchBuf)
743 FIXME("%s %p %08lx\n", debugstr_w(szComponent), lpPathBuf, *pcchBuf);
744 return INSTALLSTATE_UNKNOWN;
747 #include "winuser.h"
749 UINT WINAPI MsiMessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType, WORD wLanguageId, DWORD f)
751 FIXME("%p %s %s %u %08x %08lx\n",hWnd,debugstr_a(lpText),debugstr_a(lpCaption),uType,wLanguageId,f);
753 MessageBoxExA(hWnd,lpText,lpCaption,uType|MB_OK,wLanguageId);
755 return ERROR_CALL_NOT_IMPLEMENTED;
758 UINT WINAPI MsiMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType, WORD wLanguageId, DWORD f)
760 /*FIXME("%08lx %08lx %08lx %08lx %08lx %08lx\n",a,b,c,d,e,f);*/
761 FIXME("%p %s %s %u %08x %08lx\n",hWnd,debugstr_w(lpText),debugstr_w(lpCaption),uType,wLanguageId,f);
763 MessageBoxExW(hWnd,lpText,lpCaption,uType|MB_OK,wLanguageId);
765 return ERROR_CALL_NOT_IMPLEMENTED;
768 UINT WINAPI MsiEnumProductsA(DWORD index, LPSTR lpguid)
770 DWORD r;
771 WCHAR szwGuid[GUID_SIZE];
773 TRACE("%ld %p\n",index,lpguid);
775 if (NULL == lpguid) {
776 return ERROR_INVALID_PARAMETER;
778 r = MsiEnumProductsW(index, szwGuid);
779 if( r == ERROR_SUCCESS )
780 WideCharToMultiByte(CP_ACP, 0, szwGuid, -1, lpguid, GUID_SIZE, NULL, NULL);
782 return r;
785 UINT WINAPI MsiEnumProductsW(DWORD index, LPWSTR lpguid)
787 HKEY hkey = 0, hkeyFeatures = 0;
788 DWORD r;
789 WCHAR szKeyName[33];
791 TRACE("%ld %p\n",index,lpguid);
793 if (NULL == lpguid) {
794 return ERROR_INVALID_PARAMETER;
796 r = RegOpenKeyW(HKEY_LOCAL_MACHINE, szInstaller, &hkey);
797 if( r != ERROR_SUCCESS )
798 goto end;
800 r = RegOpenKeyW(hkey, szFeatures, &hkeyFeatures);
801 if( r != ERROR_SUCCESS )
802 goto end;
804 r = RegEnumKeyW(hkeyFeatures, index, szKeyName, GUID_SIZE);
806 unsquash_guid(szKeyName, lpguid);
808 end:
810 if( hkeyFeatures )
811 RegCloseKey(hkeyFeatures);
812 if( hkey )
813 RegCloseKey(hkey);
815 return r;
818 UINT WINAPI MsiEnumFeaturesA(LPCSTR szProduct, DWORD index,
819 LPSTR szFeature, LPSTR szParent)
821 DWORD r;
822 WCHAR szwFeature[GUID_SIZE], szwParent[GUID_SIZE];
823 LPWSTR szwProduct = NULL;
825 TRACE("%s %ld %p %p\n",debugstr_a(szProduct),index,szFeature,szParent);
827 if( szProduct )
829 UINT len = MultiByteToWideChar( CP_ACP, 0, szProduct, -1, NULL, 0 );
830 szwProduct = HeapAlloc( GetProcessHeap(), 0, len * sizeof (WCHAR) );
831 if( szwProduct )
832 MultiByteToWideChar( CP_ACP, 0, szProduct, -1, szwProduct, len );
833 else
834 return ERROR_FUNCTION_FAILED;
837 r = MsiEnumFeaturesW(szwProduct, index, szwFeature, szwParent);
838 if( r == ERROR_SUCCESS )
840 WideCharToMultiByte(CP_ACP, 0, szwFeature, -1,
841 szFeature, GUID_SIZE, NULL, NULL);
842 WideCharToMultiByte(CP_ACP, 0, szwParent, -1,
843 szParent, GUID_SIZE, NULL, NULL);
846 if( szwProduct )
847 HeapFree( GetProcessHeap(), 0, szwProduct);
849 return r;
852 UINT WINAPI MsiEnumFeaturesW(LPCWSTR szProduct, DWORD index,
853 LPWSTR szFeature, LPWSTR szParent)
855 HKEY hkey = 0, hkeyFeatures = 0, hkeyProduct = 0;
856 DWORD r, sz;
857 WCHAR szRegName[GUID_SIZE];
859 TRACE("%s %ld %p %p\n",debugstr_w(szProduct),index,szFeature,szParent);
861 if( !squash_guid(szProduct, szRegName) )
862 return ERROR_INVALID_PARAMETER;
864 r = RegOpenKeyW(HKEY_LOCAL_MACHINE, szInstaller, &hkey);
865 if( r != ERROR_SUCCESS )
866 goto end;
868 r = RegOpenKeyW(hkey, szFeatures, &hkeyFeatures);
869 if( r != ERROR_SUCCESS )
870 goto end;
872 r = RegOpenKeyW(hkeyFeatures, szRegName, &hkeyProduct);
873 if( r != ERROR_SUCCESS )
874 goto end;
876 sz = GUID_SIZE;
877 r = RegEnumValueW(hkeyProduct, index, szFeature, &sz, NULL, NULL, NULL, NULL);
879 end:
880 if( hkeyProduct )
881 RegCloseKey(hkeyProduct);
882 if( hkeyFeatures )
883 RegCloseKey(hkeyFeatures);
884 if( hkey )
885 RegCloseKey(hkey);
887 return r;
890 UINT WINAPI MsiEnumComponentsA(DWORD index, LPSTR lpguid)
892 DWORD r;
893 WCHAR szwGuid[GUID_SIZE];
895 TRACE("%ld %p\n",index,lpguid);
897 r = MsiEnumComponentsW(index, szwGuid);
898 if( r == ERROR_SUCCESS )
899 WideCharToMultiByte(CP_ACP, 0, szwGuid, -1, lpguid, GUID_SIZE, NULL, NULL);
901 return r;
904 UINT WINAPI MsiEnumComponentsW(DWORD index, LPWSTR lpguid)
906 HKEY hkey = 0, hkeyComponents = 0;
907 DWORD r;
908 WCHAR szKeyName[33];
910 TRACE("%ld %p\n",index,lpguid);
912 r = RegOpenKeyW(HKEY_LOCAL_MACHINE, szInstaller, &hkey);
913 if( r != ERROR_SUCCESS )
914 goto end;
916 r = RegOpenKeyW(hkey, szComponents, &hkeyComponents);
917 if( r != ERROR_SUCCESS )
918 goto end;
920 r = RegEnumKeyW(hkeyComponents, index, szKeyName, GUID_SIZE);
922 unsquash_guid(szKeyName, lpguid);
924 end:
926 if( hkeyComponents )
927 RegCloseKey(hkeyComponents);
928 if( hkey )
929 RegCloseKey(hkey);
931 return r;
934 UINT WINAPI MsiEnumClientsA(LPCSTR szComponent, DWORD index, LPSTR szProduct)
936 DWORD r;
937 WCHAR szwProduct[GUID_SIZE];
938 LPWSTR szwComponent = NULL;
940 TRACE("%s %ld %p\n",debugstr_a(szComponent),index,szProduct);
942 if( szComponent )
944 UINT len = MultiByteToWideChar( CP_ACP, 0, szComponent, -1, NULL, 0 );
945 szwComponent = HeapAlloc( GetProcessHeap(), 0, len * sizeof (WCHAR) );
946 if( szwComponent )
947 MultiByteToWideChar( CP_ACP, 0, szComponent, -1, szwComponent, len );
948 else
949 return ERROR_FUNCTION_FAILED;
952 r = MsiEnumClientsW(szComponent?szwComponent:NULL, index, szwProduct);
953 if( r == ERROR_SUCCESS )
955 WideCharToMultiByte(CP_ACP, 0, szwProduct, -1,
956 szProduct, GUID_SIZE, NULL, NULL);
959 if( szwComponent )
960 HeapFree( GetProcessHeap(), 0, szwComponent);
962 return r;
965 UINT WINAPI MsiEnumClientsW(LPCWSTR szComponent, DWORD index, LPWSTR szProduct)
967 HKEY hkey = 0, hkeyComponents = 0, hkeyComp = 0;
968 DWORD r, sz;
969 WCHAR szRegName[GUID_SIZE], szValName[GUID_SIZE];
971 TRACE("%s %ld %p\n",debugstr_w(szComponent),index,szProduct);
973 if( !squash_guid(szComponent, szRegName) )
974 return ERROR_INVALID_PARAMETER;
976 r = RegOpenKeyW(HKEY_LOCAL_MACHINE, szInstaller, &hkey);
977 if( r != ERROR_SUCCESS )
978 goto end;
980 r = RegOpenKeyW(hkey, szComponents, &hkeyComponents);
981 if( r != ERROR_SUCCESS )
982 goto end;
984 r = RegOpenKeyW(hkeyComponents, szRegName, &hkeyComp);
985 if( r != ERROR_SUCCESS )
986 goto end;
988 sz = GUID_SIZE;
989 r = RegEnumValueW(hkeyComp, index, szValName, &sz, NULL, NULL, NULL, NULL);
990 if( r != ERROR_SUCCESS )
991 goto end;
993 unsquash_guid(szValName, szProduct);
995 end:
996 if( hkeyComp )
997 RegCloseKey(hkeyComp);
998 if( hkeyComponents )
999 RegCloseKey(hkeyComponents);
1000 if( hkey )
1001 RegCloseKey(hkey);
1003 return r;
1006 UINT WINAPI MsiEnumComponentQualifiersA(
1007 LPSTR szComponent, DWORD iIndex, LPSTR lpQualifierBuf, DWORD* pcchQualifierBuf, LPSTR lpApplicationDataBuf, DWORD* pcchApplicationDataBuf)
1009 FIXME("%s 0x%08lx %p %p %p %p\n", debugstr_a(szComponent), iIndex, lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf, pcchApplicationDataBuf);
1010 return ERROR_CALL_NOT_IMPLEMENTED;
1013 UINT WINAPI MsiEnumComponentQualifiersW(
1014 LPWSTR szComponent, DWORD iIndex, LPWSTR lpQualifierBuf, DWORD* pcchQualifierBuf, LPWSTR lpApplicationDataBuf, DWORD* pcchApplicationDataBuf)
1016 FIXME("%s 0x%08lx %p %p %p %p\n", debugstr_w(szComponent), iIndex, lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf, pcchApplicationDataBuf);
1017 return ERROR_CALL_NOT_IMPLEMENTED;
1020 UINT WINAPI MsiProvideAssemblyA(
1021 LPCSTR szAssemblyName, LPCSTR szAppContext, DWORD dwInstallMode, DWORD dwAssemblyInfo, LPSTR lpPathBuf, DWORD* pcchPathBuf)
1023 FIXME("%s %s 0x%08lx 0x%08lx %p %p\n",
1024 debugstr_a(szAssemblyName), debugstr_a(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf, pcchPathBuf);
1025 return ERROR_CALL_NOT_IMPLEMENTED;
1028 UINT WINAPI MsiProvideAssemblyW(
1029 LPCWSTR szAssemblyName, LPCWSTR szAppContext, DWORD dwInstallMode, DWORD dwAssemblyInfo, LPWSTR lpPathBuf, DWORD* pcchPathBuf)
1031 FIXME("%s %s 0x%08lx 0x%08lx %p %p\n",
1032 debugstr_w(szAssemblyName), debugstr_w(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf, pcchPathBuf);
1033 return ERROR_CALL_NOT_IMPLEMENTED;
1036 UINT WINAPI MsiProvideComponentFromDescriptorA( LPCSTR szDescriptor, LPSTR szPath, DWORD *pcchPath, DWORD *pcchArgs )
1038 FIXME("%s %p %p %p\n", debugstr_a(szDescriptor), szPath, pcchPath, pcchArgs );
1039 return ERROR_CALL_NOT_IMPLEMENTED;
1042 UINT WINAPI MsiProvideComponentFromDescriptorW( LPCWSTR szDescriptor, LPWSTR szPath, DWORD *pcchPath, DWORD *pcchArgs )
1044 FIXME("%s %p %p %p\n", debugstr_w(szDescriptor), szPath, pcchPath, pcchArgs );
1045 return ERROR_CALL_NOT_IMPLEMENTED;
1048 HRESULT WINAPI MsiGetFileSignatureInformationA(
1049 LPCSTR szSignedObjectPath, DWORD dwFlags, PCCERT_CONTEXT* ppcCertContext, BYTE* pbHashData, DWORD* pcbHashData)
1051 FIXME("%s 0x%08lx %p %p %p\n", debugstr_a(szSignedObjectPath), dwFlags, ppcCertContext, pbHashData, pcbHashData);
1052 return ERROR_CALL_NOT_IMPLEMENTED;
1055 HRESULT WINAPI MsiGetFileSignatureInformationW(
1056 LPCWSTR szSignedObjectPath, DWORD dwFlags, PCCERT_CONTEXT* ppcCertContext, BYTE* pbHashData, DWORD* pcbHashData)
1058 FIXME("%s 0x%08lx %p %p %p\n", debugstr_w(szSignedObjectPath), dwFlags, ppcCertContext, pbHashData, pcbHashData);
1059 return ERROR_CALL_NOT_IMPLEMENTED;
1062 UINT WINAPI MsiGetProductPropertyA( MSIHANDLE hProduct, LPCSTR szProperty,
1063 LPSTR szValue, DWORD *pccbValue )
1065 FIXME("%ld %s %p %p\n", hProduct, debugstr_a(szProperty), szValue, pccbValue);
1066 return ERROR_CALL_NOT_IMPLEMENTED;
1069 UINT WINAPI MsiGetProductPropertyW( MSIHANDLE hProduct, LPCWSTR szProperty,
1070 LPWSTR szValue, DWORD *pccbValue )
1072 FIXME("%ld %s %p %p\n", hProduct, debugstr_w(szProperty), szValue, pccbValue);
1073 return ERROR_CALL_NOT_IMPLEMENTED;
1076 UINT WINAPI MsiVerifyPackageA( LPCSTR szPackage )
1078 FIXME("%s\n", debugstr_a(szPackage) );
1079 return ERROR_CALL_NOT_IMPLEMENTED;
1082 UINT WINAPI MsiVerifyPackageW( LPCWSTR szPackage )
1084 FIXME("%s\n", debugstr_w(szPackage) );
1085 return ERROR_CALL_NOT_IMPLEMENTED;
1088 /******************************************************************
1089 * DllMain
1091 * @todo: maybe we can check here if MsiServer service is declared no ?
1093 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
1094 if (fdwReason == DLL_PROCESS_ATTACH) {
1095 DisableThreadLibraryCalls(hinstDLL);
1097 * UI Initialization
1099 gUILevel = INSTALLUILEVEL_BASIC;
1100 gUIhwnd = 0;
1101 gUIHandler = NULL;
1102 gUIFilter = 0;
1103 gUIContext = NULL;
1104 /* FIXME: Initialisation */
1105 } else if (fdwReason == DLL_PROCESS_DETACH) {
1106 /* FIXME: Cleanup */
1109 static const WCHAR szMSIServerSvc[] = { 'M','S','I','S','e','r','v','e','r',0 };
1110 static const WCHAR szNull[] = { 0 };
1111 if (!strcmpW(lpServiceName, szMSIServerSvc)) {
1112 hKey = CreateServiceW(hSCManager,
1113 szMSIServerSvc,
1114 szMSIServerSvc,
1115 SC_MANAGER_ALL_ACCESS,
1116 SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS,
1117 SERVICE_AUTO_START,
1118 SERVICE_ERROR_IGNORE,
1119 szNull,
1120 NULL,
1121 NULL,
1122 NULL,
1123 NULL,
1124 szNull);
1126 return TRUE;
1129 typedef struct {
1130 /* IUnknown fields */
1131 ICOM_VFIELD(IClassFactory);
1132 DWORD ref;
1133 } IClassFactoryImpl;
1135 static HRESULT WINAPI MsiCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
1136 ICOM_THIS(IClassFactoryImpl,iface);
1137 FIXME("(%p, %s, %p): stub\n",This,debugstr_guid(riid),ppobj);
1138 return E_NOINTERFACE;
1141 static ULONG WINAPI MsiCF_AddRef(LPCLASSFACTORY iface) {
1142 ICOM_THIS(IClassFactoryImpl,iface);
1143 return ++(This->ref);
1146 static ULONG WINAPI MsiCF_Release(LPCLASSFACTORY iface) {
1147 ICOM_THIS(IClassFactoryImpl,iface);
1148 /* static class, won't be freed */
1149 return --(This->ref);
1152 static HRESULT WINAPI MsiCF_CreateInstance(LPCLASSFACTORY iface, LPUNKNOWN pOuter, REFIID riid, LPVOID *ppobj) {
1153 ICOM_THIS(IClassFactoryImpl,iface);
1154 FIXME ("(%p, %p, %s, %p): to implement\n", This, pOuter, debugstr_guid(riid), ppobj);
1155 return 0;
1158 static HRESULT WINAPI MsiCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
1159 ICOM_THIS(IClassFactoryImpl,iface);
1160 FIXME("(%p, %d): stub\n", This, dolock);
1161 return S_OK;
1164 static ICOM_VTABLE(IClassFactory) MsiCF_Vtbl = {
1165 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1166 MsiCF_QueryInterface,
1167 MsiCF_AddRef,
1168 MsiCF_Release,
1169 MsiCF_CreateInstance,
1170 MsiCF_LockServer
1173 static IClassFactoryImpl Msi_CF = {&MsiCF_Vtbl, 1 };
1175 /******************************************************************
1176 * DllGetClassObject (MSI.@)
1178 HRESULT WINAPI MSI_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) {
1179 FIXME("(%s, %s, %p): almost a stub.\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
1180 if (IsEqualCLSID (rclsid, &CLSID_IMsiServer)) {
1181 *ppv = (LPVOID) &Msi_CF;
1182 IClassFactory_AddRef((IClassFactory*)*ppv);
1183 return S_OK;
1184 } else if (IsEqualCLSID (rclsid, &CLSID_IMsiServerMessage)) {
1185 *ppv = (LPVOID) &Msi_CF;
1186 IClassFactory_AddRef((IClassFactory*)*ppv);
1187 return S_OK;
1188 } else if (IsEqualCLSID (rclsid, &CLSID_IMsiServerX1)) {
1189 *ppv = (LPVOID) &Msi_CF;
1190 IClassFactory_AddRef((IClassFactory*)*ppv);
1191 return S_OK;
1192 } else if (IsEqualCLSID (rclsid, &CLSID_IMsiServerX2)) {
1193 *ppv = (LPVOID) &Msi_CF;
1194 IClassFactory_AddRef((IClassFactory*)*ppv);
1195 return S_OK;
1196 } else if (IsEqualCLSID (rclsid, &CLSID_IMsiServerX3)) {
1197 *ppv = (LPVOID) &Msi_CF;
1198 IClassFactory_AddRef((IClassFactory*)*ppv);
1199 return S_OK;
1201 WARN("(%s, %s, %p): no interface found.\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
1202 return CLASS_E_CLASSNOTAVAILABLE;
1205 /******************************************************************
1206 * DllGetVerison (MSI.@)
1208 HRESULT WINAPI MSI_DllGetVersion(DLLVERSIONINFO *pdvi)
1210 TRACE("%p\n",pdvi);
1212 if (pdvi->cbSize != sizeof(DLLVERSIONINFO))
1213 return E_INVALIDARG;
1215 pdvi->dwMajorVersion = MSI_MAJORVERSION;
1216 pdvi->dwMinorVersion = MSI_MINORVERSION;
1217 pdvi->dwBuildNumber = MSI_BUILDNUMBER;
1218 pdvi->dwPlatformID = 1;
1220 return S_OK;
1223 /******************************************************************
1224 * DllCanUnloadNow (MSI.@)
1226 BOOL WINAPI MSI_DllCanUnloadNow(void)
1228 return S_FALSE;
1231 UINT WINAPI MsiEnumRelatedProductsA (LPCSTR lpUpgradeCode, DWORD dwReserved,
1232 DWORD iProductIndex, LPSTR lpProductBuf)
1234 FIXME("STUB: (%s, %li %li %s)\n",lpUpgradeCode, dwReserved, iProductIndex,
1235 lpProductBuf);
1236 return ERROR_CALL_NOT_IMPLEMENTED;