include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / programs / wmic / main.c
blob02a07f03d2ebb58289c62e3bbdf57c85aaffc579
1 /*
2 * Copyright 2010 Louis Lenders
3 * Copyright 2012 Hans Leidekker for CodeWeavers
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #define COBJMACROS
22 #include <fcntl.h>
23 #include <io.h>
24 #include <locale.h>
25 #include <stdio.h>
26 #include "windows.h"
27 #include "ocidl.h"
28 #include "initguid.h"
29 #include "objidl.h"
30 #include "wbemcli.h"
31 #include "shellapi.h"
32 #include "wmic.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(wmic);
38 #define MAX_STRING 4096
39 static const struct
41 const WCHAR *alias;
42 const WCHAR *class;
44 alias_map[] =
46 { L"baseboard", L"Win32_BaseBoard" },
47 { L"bios", L"Win32_BIOS" },
48 { L"computersystem", L"Win32_ComputerSystem" },
49 { L"cpu", L"Win32_Processor" },
50 { L"csproduct", L"Win32_ComputerSystemProduct" },
51 { L"diskdrive", L"Win32_DiskDrive" },
52 { L"logicaldisk", L"Win32_LogicalDisk" },
53 { L"memorychip", L"Win32_PhysicalMemory" },
54 { L"nic", L"Win32_NetworkAdapter" },
55 { L"nicconfig", L"Win32_NetworkAdapterConfiguration" },
56 { L"os", L"Win32_OperatingSystem" },
57 { L"process", L"Win32_Process" },
58 { L"systemenclosure", L"Win32_SystemEnclosure" },
61 static const WCHAR *find_class( const WCHAR *alias )
63 unsigned int i;
65 for (i = 0; i < ARRAY_SIZE(alias_map); i++)
67 if (!wcsicmp( alias, alias_map[i].alias )) return alias_map[i].class;
69 return NULL;
72 static int WINAPIV output_string( const WCHAR *msg, ... )
74 int count, bom_count = 0;
75 static BOOL bom;
76 va_list va_args;
78 if (!bom)
80 if (GetFileType((HANDLE)_get_osfhandle( STDOUT_FILENO )) == FILE_TYPE_DISK)
82 _setmode( STDOUT_FILENO, _O_U16TEXT );
83 bom_count = wprintf( L"\xfeff" );
85 bom = TRUE;
88 va_start( va_args, msg );
89 count = vwprintf( msg, va_args );
90 va_end( va_args );
91 return count + bom_count;
94 static int output_error( int msg )
96 WCHAR buffer[8192];
98 LoadStringW( GetModuleHandleW(NULL), msg, buffer, ARRAY_SIZE(buffer));
99 return fwprintf( stderr, L"%s", buffer );
102 static int output_text( const WCHAR *str, ULONG column_width )
104 return output_string( L"%-*s", column_width, str );
107 static int output_newline( void )
109 return output_string( L"\n" );
112 static WCHAR *strip_spaces( WCHAR *start )
114 WCHAR *str = start, *end = start + wcslen( start ) - 1;
115 while (*str == ' ') str++;
116 while (end >= start && *end == ' ') *end-- = 0;
117 return str;
120 static HRESULT append_property( IWbemClassObject *obj, const WCHAR *prop, WCHAR *proplist )
122 HRESULT hr;
124 if (FAILED(hr = IWbemClassObject_Get( obj, prop, 0, NULL, NULL, NULL ))) return hr;
125 if (*proplist) wcscat( proplist, L"," );
126 wcscat( proplist, prop );
127 return S_OK;
130 static HRESULT process_property_list( IWbemClassObject *obj, int argc, WCHAR *argv[], WCHAR **ret )
132 WCHAR *str = NULL, *ctx, *ptr, *stripped;
133 UINT i, len = 0;
134 HRESULT hr;
136 for (i = 0; i < argc; i++) len += wcslen( argv[i] );
137 if (!(stripped = malloc( (len + 1) * sizeof(*stripped) ))) return E_OUTOFMEMORY;
138 *stripped = 0;
140 for (i = 0; i < argc; i++)
142 if (!(str = wcsdup( argv[i] )))
144 free( stripped );
145 return E_OUTOFMEMORY;
148 /* Validate that every requested property is supported. */
149 ptr = wcstok_s( str, L",", &ctx );
150 if (!ptr)
152 ptr = strip_spaces( str );
153 if (FAILED(hr = append_property( obj, ptr, stripped ))) goto error;
155 else
157 while (ptr)
159 ptr = strip_spaces( ptr );
160 if (FAILED(hr = append_property( obj, ptr, stripped ))) goto error;
161 ptr = wcstok_s( NULL, L",", &ctx );
164 free( str );
167 *ret = stripped;
168 return S_OK;
170 error:
171 free( str );
172 free( stripped );
173 return hr;
176 static void convert_to_bstr( VARIANT *v )
178 BSTR out = NULL;
179 VARTYPE vt;
181 if (SUCCEEDED(VariantChangeType( v, v, 0, VT_BSTR ))) return;
182 vt = V_VT(v);
183 if (vt == (VT_ARRAY | VT_BSTR))
185 unsigned int i, count, len;
186 BSTR *strings;
187 WCHAR *ptr;
189 if (FAILED(SafeArrayAccessData( V_ARRAY(v), (void **)&strings )))
191 WINE_ERR( "Could not access array.\n" );
192 goto done;
194 count = V_ARRAY(v)->rgsabound->cElements;
195 len = 0;
196 for (i = 0; i < count; ++i)
197 len += wcslen( strings[i] );
198 len += count * 2 + 2;
199 if (count) len += 2 * (count - 1);
200 out = SysAllocStringLen( NULL, len );
201 ptr = out;
202 *ptr++ = '{';
203 for (i = 0; i < count; ++i)
205 if (i)
207 memcpy( ptr, L", ", 2 * sizeof(*ptr) );
208 ptr += 2;
210 *ptr++ = '\"';
211 len = wcslen( strings[i] );
212 memcpy( ptr, strings[i], len * sizeof(*ptr) );
213 ptr += len;
214 *ptr++ = '\"';
216 *ptr++ = '}';
217 *ptr = 0;
218 SafeArrayUnaccessData( V_ARRAY(v) );
220 done:
221 VariantClear( v );
222 V_VT(v) = VT_BSTR;
223 V_BSTR(v) = out ? out : SysAllocString( L"" );
224 if (vt != VT_NULL && vt != VT_EMPTY && !out)
225 WINE_FIXME( "Could not convert variant, vt %u.\n", vt );
228 static int query_prop( const WCHAR *class, int argc, WCHAR *argv[] )
230 HRESULT hr;
231 IWbemLocator *locator = NULL;
232 IWbemServices *services = NULL;
233 IEnumWbemClassObject *result = NULL;
234 LONG flags = WBEM_FLAG_RETURN_IMMEDIATELY;
235 BSTR path = NULL, wql = NULL, query = NULL, name, str = NULL;
236 WCHAR *proplist = NULL;
237 int len, ret = -1;
238 IWbemClassObject *obj;
239 ULONG count, width = 0;
240 VARIANT v;
241 int i;
243 WINE_TRACE( "%s", debugstr_w(class) );
244 for (i = 0; i < argc; i++) WINE_TRACE( " %s", debugstr_w(argv[i]) );
245 WINE_TRACE( "\n" );
247 CoInitialize( NULL );
248 CoInitializeSecurity( NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT,
249 RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL );
251 hr = CoCreateInstance( &CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, &IID_IWbemLocator,
252 (void **)&locator );
253 if (hr != S_OK) goto done;
255 if (!(path = SysAllocString(L"ROOT\\CIMV2" ))) goto done;
256 hr = IWbemLocator_ConnectServer( locator, path, NULL, NULL, NULL, 0, NULL, NULL, &services );
257 if (hr != S_OK) goto done;
259 if (!(str = SysAllocString( class ))) goto done;
260 hr = IWbemServices_GetObject( services, str, 0, NULL, &obj, NULL );
261 SysFreeString( str );
262 if (hr != S_OK)
264 WARN("Unrecognized class %s.\n", debugstr_w(class));
265 goto done;
268 /* Check that this class supports all requested properties. */
269 hr = process_property_list( obj, argc, argv, &proplist );
270 IWbemClassObject_Release( obj );
271 if (FAILED(hr))
273 output_error( STRING_INVALID_QUERY );
274 goto done;
277 len = lstrlenW( class ) + lstrlenW( proplist ) + ARRAY_SIZE(L"SELECT * FROM ");
278 if (!(query = SysAllocStringLen( NULL, len ))) goto done;
279 swprintf( query, len, L"SELECT %s FROM %s", proplist, class );
281 if (!(wql = SysAllocString(L"WQL" ))) goto done;
282 hr = IWbemServices_ExecQuery( services, wql, query, flags, NULL, &result );
283 if (hr != S_OK) goto done;
285 for (;;) /* get column width */
287 IEnumWbemClassObject_Next( result, WBEM_INFINITE, 1, &obj, &count );
288 if (!count) break;
290 IWbemClassObject_BeginEnumeration( obj, 0 );
291 while (IWbemClassObject_Next( obj, 0, &name, &v, NULL, NULL ) == S_OK)
293 convert_to_bstr( &v );
294 width = max( lstrlenW( V_BSTR( &v ) ), width );
295 VariantClear( &v );
296 SysFreeString( name );
299 IWbemClassObject_Release( obj );
301 width += 2;
303 /* Header */
304 IEnumWbemClassObject_Reset( result );
305 IEnumWbemClassObject_Next( result, WBEM_INFINITE, 1, &obj, &count );
306 if (count)
308 IWbemClassObject_BeginEnumeration( obj, 0 );
309 while (IWbemClassObject_Next( obj, 0, &name, NULL, NULL, NULL ) == S_OK)
311 output_text( name, width );
312 SysFreeString( name );
314 output_newline();
315 IWbemClassObject_Release( obj );
318 /* Values */
319 IEnumWbemClassObject_Reset( result );
320 for (;;)
322 IEnumWbemClassObject_Next( result, WBEM_INFINITE, 1, &obj, &count );
323 if (!count) break;
324 IWbemClassObject_BeginEnumeration( obj, 0 );
325 while (IWbemClassObject_Next( obj, 0, NULL, &v, NULL, NULL ) == S_OK)
327 convert_to_bstr( &v );
328 output_text( V_BSTR( &v ), width );
329 VariantClear( &v );
331 output_newline();
332 IWbemClassObject_Release( obj );
334 ret = 0;
336 done:
337 if (result) IEnumWbemClassObject_Release( result );
338 if (services) IWbemServices_Release( services );
339 if (locator) IWbemLocator_Release( locator );
340 SysFreeString( path );
341 SysFreeString( query );
342 SysFreeString( wql );
343 free( proplist );
344 CoUninitialize();
345 return ret;
348 static int process_args( int argc, WCHAR *argv[] )
350 const WCHAR *class;
351 int i;
353 for (i = 0; i < argc && argv[i][0] == '/'; i++)
354 WINE_FIXME( "switch %s not supported\n", debugstr_w(argv[i]) );
356 if (i >= argc)
357 goto not_supported;
359 if (!wcsicmp( argv[i], L"quit" ) || !wcsicmp( argv[i], L"exit" ))
361 return 0;
364 if (!wcsicmp( argv[i], L"class" ) || !wcsicmp( argv[i], L"context" ))
366 WINE_FIXME( "command %s not supported\n", debugstr_w(argv[i]) );
367 goto not_supported;
370 if (!wcsicmp( argv[i], L"path" ))
372 if (++i >= argc)
374 output_error( STRING_INVALID_PATH );
375 return 1;
377 class = argv[i];
379 else
381 class = find_class( argv[i] );
382 if (!class)
384 output_error( STRING_ALIAS_NOT_FOUND );
385 return 1;
389 if (++i >= argc)
390 goto not_supported;
392 if (!wcsicmp( argv[i], L"get" ))
394 if (++i >= argc)
395 goto not_supported;
396 return query_prop( class, argc - i, argv + i );
399 not_supported:
400 output_error( STRING_COMMAND_NOT_SUPPORTED );
401 return 1;
404 int __cdecl wmain(int argc, WCHAR *argv[])
406 WCHAR cmd[MAX_STRING];
407 int ret = 0;
409 setlocale( LC_ALL, "" );
411 if (argc == 1)
413 fputws( L"wmic:root\\cli>", stdout );
415 while (fgetws( cmd, sizeof(cmd), stdin ) != NULL)
417 const WCHAR *stripped;
419 cmd[wcslen(cmd) - 1] = 0; /* remove trailing '\n' */
420 stripped = strip_spaces( cmd );
422 WINE_TRACE( "command: %s\n", debugstr_w(stripped) );
423 if (!wcsicmp( stripped, L"exit" ) || !wcsicmp( stripped, L"quit" ))
424 return 0;
426 if (!stripped[0])
427 output_error( STRING_USAGE );
428 else
430 int new_argc;
431 WCHAR **new_argv;
433 if (!(new_argv = CommandLineToArgvW( stripped, &new_argc ))) return 1;
434 ret = process_args( new_argc, new_argv );
435 LocalFree( new_argv );
437 output_newline();
439 fputws( L"wmic:root\\cli>", stdout );
441 return ret;
444 return process_args( argc - 1, argv + 1 );