ntdll: Implement NtCreateToken().
[wine.git] / programs / wmic / main.c
blob936fe45139de6318e381f49b36fd31985bb87e3c
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 "wmic.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(wmic);
37 static const struct
39 const WCHAR *alias;
40 const WCHAR *class;
42 alias_map[] =
44 { L"bios", L"Win32_BIOS" },
45 { L"computersystem", L"Win32_ComputerSystem" },
46 { L"cpu", L"Win32_Processor" },
47 { L"LogicalDisk", L"Win32_LogicalDisk" },
48 { L"nic", L"Win32_NetworkAdapter" },
49 { L"os", L"Win32_OperatingSystem" },
50 { L"process", L"Win32_Process" },
51 { L"baseboard", L"Win32_BaseBoard" },
52 { L"diskdrive", L"Win32_DiskDrive" },
53 { L"memorychip", L"Win32_PhysicalMemory" },
54 { L"nicconfig", L"Win32_NetworkAdapterConfiguration" },
57 static const WCHAR *find_class( const WCHAR *alias )
59 unsigned int i;
61 for (i = 0; i < ARRAY_SIZE(alias_map); i++)
63 if (!wcsicmp( alias, alias_map[i].alias )) return alias_map[i].class;
65 return NULL;
68 static int WINAPIV output_string( const WCHAR *msg, ... )
70 int count, bom_count = 0;
71 static BOOL bom;
72 va_list va_args;
74 if (!bom)
76 if (GetFileType((HANDLE)_get_osfhandle( STDOUT_FILENO )) == FILE_TYPE_DISK)
78 _setmode( STDOUT_FILENO, _O_U16TEXT );
79 bom_count = wprintf( L"\xfeff" );
81 bom = TRUE;
84 va_start( va_args, msg );
85 count = vwprintf( msg, va_args );
86 va_end( va_args );
87 return count + bom_count;
90 static int output_error( int msg )
92 WCHAR buffer[8192];
94 LoadStringW( GetModuleHandleW(NULL), msg, buffer, ARRAY_SIZE(buffer));
95 return fwprintf( stderr, L"%s", buffer );
98 static int output_text( const WCHAR *str, ULONG column_width )
100 return output_string( L"%-*s", column_width, str );
103 static int output_newline( void )
105 return output_string( L"\n" );
108 static WCHAR * strip_spaces(WCHAR *start)
110 WCHAR *str = start, *end;
112 while (*str == ' ')
113 str++;
115 end = start + lstrlenW(start) - 1;
116 while (end >= start && *end == ' ')
118 *end = '\0';
119 end--;
122 return str;
125 static HRESULT process_property_list( IWbemClassObject *obj, const WCHAR *proplist, WCHAR **ret )
127 WCHAR *p, *ctx, *ptr, *stripped;
128 HRESULT hr = S_OK;
130 if (!(p = wcsdup( proplist ))) return E_OUTOFMEMORY;
132 if (!(stripped = malloc( (wcslen( proplist ) + 1) * sizeof(**ret) )))
134 free( p );
135 return E_OUTOFMEMORY;
137 *stripped = 0;
139 /* Validate that every requested property is supported. */
140 ptr = wcstok_s( p, L",", &ctx );
141 while (ptr)
143 ptr = strip_spaces( ptr );
145 if (FAILED(IWbemClassObject_Get( obj, ptr, 0, NULL, NULL, NULL )))
147 hr = E_FAIL;
148 break;
150 if (*stripped) wcscat( stripped, L"," );
151 wcscat( stripped, ptr );
152 ptr = wcstok_s( NULL, L",", &ctx );
154 free( p );
156 if (SUCCEEDED(hr))
157 *ret = stripped;
158 else
160 free( stripped );
161 *ret = NULL;
164 return hr;
167 static void convert_to_bstr( VARIANT *v )
169 BSTR out = NULL;
170 VARTYPE vt;
172 if (SUCCEEDED(VariantChangeType( v, v, 0, VT_BSTR ))) return;
173 vt = V_VT(v);
174 if (vt == (VT_ARRAY | VT_BSTR))
176 unsigned int i, count, len;
177 BSTR *strings;
178 WCHAR *ptr;
180 if (FAILED(SafeArrayAccessData( V_ARRAY(v), (void **)&strings )))
182 WINE_ERR( "Could not access array.\n" );
183 goto done;
185 count = V_ARRAY(v)->rgsabound->cElements;
186 len = 0;
187 for (i = 0; i < count; ++i)
188 len += wcslen( strings[i] );
189 len += count * 2 + 2;
190 if (count) len += 2 * (count - 1);
191 out = SysAllocStringLen( NULL, len );
192 ptr = out;
193 *ptr++ = '{';
194 for (i = 0; i < count; ++i)
196 if (i)
198 memcpy( ptr, L", ", 2 * sizeof(*ptr) );
199 ptr += 2;
201 *ptr++ = '\"';
202 len = wcslen( strings[i] );
203 memcpy( ptr, strings[i], len * sizeof(*ptr) );
204 ptr += len;
205 *ptr++ = '\"';
207 *ptr++ = '}';
208 *ptr = 0;
209 SafeArrayUnaccessData( V_ARRAY(v) );
211 done:
212 VariantClear( v );
213 V_VT(v) = VT_BSTR;
214 V_BSTR(v) = out ? out : SysAllocString( L"" );
215 if (vt != VT_NULL && vt != VT_EMPTY && !out)
216 WINE_FIXME( "Could not convert variant, vt %u.\n", vt );
219 static int query_prop( const WCHAR *class, const WCHAR *propnames )
221 HRESULT hr;
222 IWbemLocator *locator = NULL;
223 IWbemServices *services = NULL;
224 IEnumWbemClassObject *result = NULL;
225 LONG flags = WBEM_FLAG_RETURN_IMMEDIATELY;
226 BSTR path = NULL, wql = NULL, query = NULL, name, str = NULL;
227 WCHAR *proplist = NULL;
228 int len, ret = -1;
229 IWbemClassObject *obj;
230 ULONG count, width = 0;
231 VARIANT v;
233 WINE_TRACE("%s, %s\n", debugstr_w(class), debugstr_w(propnames));
235 CoInitialize( NULL );
236 CoInitializeSecurity( NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT,
237 RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL );
239 hr = CoCreateInstance( &CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, &IID_IWbemLocator,
240 (void **)&locator );
241 if (hr != S_OK) goto done;
243 if (!(path = SysAllocString(L"ROOT\\CIMV2" ))) goto done;
244 hr = IWbemLocator_ConnectServer( locator, path, NULL, NULL, NULL, 0, NULL, NULL, &services );
245 if (hr != S_OK) goto done;
247 if (!(str = SysAllocString( class ))) goto done;
248 hr = IWbemServices_GetObject( services, str, 0, NULL, &obj, NULL );
249 SysFreeString( str );
250 if (hr != S_OK)
252 WARN("Unrecognized class %s.\n", debugstr_w(class));
253 goto done;
256 /* Check that this class supports all requested properties. */
257 hr = process_property_list( obj, propnames, &proplist );
258 IWbemClassObject_Release( obj );
259 if (FAILED(hr))
261 output_error( STRING_INVALID_QUERY );
262 goto done;
265 len = lstrlenW( class ) + lstrlenW( proplist ) + ARRAY_SIZE(L"SELECT * FROM ");
266 if (!(query = SysAllocStringLen( NULL, len ))) goto done;
267 swprintf( query, len, L"SELECT %s FROM %s", proplist, class );
269 if (!(wql = SysAllocString(L"WQL" ))) goto done;
270 hr = IWbemServices_ExecQuery( services, wql, query, flags, NULL, &result );
271 if (hr != S_OK) goto done;
273 for (;;) /* get column width */
275 IEnumWbemClassObject_Next( result, WBEM_INFINITE, 1, &obj, &count );
276 if (!count) break;
278 IWbemClassObject_BeginEnumeration( obj, 0 );
279 while (IWbemClassObject_Next( obj, 0, &name, &v, NULL, NULL ) == S_OK)
281 convert_to_bstr( &v );
282 width = max( lstrlenW( V_BSTR( &v ) ), width );
283 VariantClear( &v );
284 SysFreeString( name );
287 IWbemClassObject_Release( obj );
289 width += 2;
291 /* Header */
292 IEnumWbemClassObject_Reset( result );
293 IEnumWbemClassObject_Next( result, WBEM_INFINITE, 1, &obj, &count );
294 if (count)
296 IWbemClassObject_BeginEnumeration( obj, 0 );
297 while (IWbemClassObject_Next( obj, 0, &name, NULL, NULL, NULL ) == S_OK)
299 output_text( name, width );
300 SysFreeString( name );
302 output_newline();
303 IWbemClassObject_Release( obj );
306 /* Values */
307 IEnumWbemClassObject_Reset( result );
308 for (;;)
310 IEnumWbemClassObject_Next( result, WBEM_INFINITE, 1, &obj, &count );
311 if (!count) break;
312 IWbemClassObject_BeginEnumeration( obj, 0 );
313 while (IWbemClassObject_Next( obj, 0, NULL, &v, NULL, NULL ) == S_OK)
315 convert_to_bstr( &v );
316 output_text( V_BSTR( &v ), width );
317 VariantClear( &v );
319 output_newline();
320 IWbemClassObject_Release( obj );
322 ret = 0;
324 done:
325 if (result) IEnumWbemClassObject_Release( result );
326 if (services) IWbemServices_Release( services );
327 if (locator) IWbemLocator_Release( locator );
328 SysFreeString( path );
329 SysFreeString( query );
330 SysFreeString( wql );
331 free( proplist );
332 CoUninitialize();
333 return ret;
336 int __cdecl wmain(int argc, WCHAR *argv[])
338 const WCHAR *class, *value;
339 int i;
341 setlocale( LC_ALL, "" );
343 for (i = 1; i < argc && argv[i][0] == '/'; i++)
344 WINE_FIXME( "command line switch %s not supported\n", debugstr_w(argv[i]) );
346 if (i >= argc)
347 goto not_supported;
349 if (!wcsicmp( argv[i], L"quit" ) || !wcsicmp( argv[i], L"exit" ))
351 return 0;
354 if (!wcsicmp( argv[i], L"class") || !wcsicmp( argv[i], L"context" ))
356 WINE_FIXME( "command %s not supported\n", debugstr_w(argv[i]) );
357 goto not_supported;
360 if (!wcsicmp( argv[i], L"path" ))
362 if (++i >= argc)
364 output_error( STRING_INVALID_PATH );
365 return 1;
367 class = argv[i];
369 else
371 class = find_class( argv[i] );
372 if (!class)
374 output_error( STRING_ALIAS_NOT_FOUND );
375 return 1;
379 if (++i >= argc)
380 goto not_supported;
382 if (!wcsicmp( argv[i], L"get" ))
384 if (++i >= argc)
385 goto not_supported;
386 value = argv[i];
387 return query_prop( class, value );
390 not_supported:
391 output_error( STRING_CMDLINE_NOT_SUPPORTED );
392 return 1;