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
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(wmic
);
38 #define MAX_STRING 4096
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
)
65 for (i
= 0; i
< ARRAY_SIZE(alias_map
); i
++)
67 if (!wcsicmp( alias
, alias_map
[i
].alias
)) return alias_map
[i
].class;
72 static int WINAPIV
output_string( const WCHAR
*msg
, ... )
74 int count
, bom_count
= 0;
80 if (GetFileType((HANDLE
)_get_osfhandle( STDOUT_FILENO
)) == FILE_TYPE_DISK
)
82 _setmode( STDOUT_FILENO
, _O_U16TEXT
);
83 bom_count
= wprintf( L
"\xfeff" );
88 va_start( va_args
, msg
);
89 count
= vwprintf( msg
, va_args
);
91 return count
+ bom_count
;
94 static int output_error( int msg
)
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;
120 static HRESULT
append_property( IWbemClassObject
*obj
, const WCHAR
*prop
, WCHAR
*proplist
)
124 if (FAILED(hr
= IWbemClassObject_Get( obj
, prop
, 0, NULL
, NULL
, NULL
))) return hr
;
125 if (*proplist
) wcscat( proplist
, L
"," );
126 wcscat( proplist
, prop
);
130 static HRESULT
process_property_list( IWbemClassObject
*obj
, int argc
, WCHAR
*argv
[], WCHAR
**ret
)
132 WCHAR
*str
= NULL
, *ctx
, *ptr
, *stripped
;
136 for (i
= 0; i
< argc
; i
++) len
+= wcslen( argv
[i
] );
137 if (!(stripped
= malloc( (len
+ 1) * sizeof(*stripped
) ))) return E_OUTOFMEMORY
;
140 for (i
= 0; i
< argc
; i
++)
142 if (!(str
= wcsdup( argv
[i
] )))
145 return E_OUTOFMEMORY
;
148 /* Validate that every requested property is supported. */
149 ptr
= wcstok_s( str
, L
",", &ctx
);
152 ptr
= strip_spaces( str
);
153 if (FAILED(hr
= append_property( obj
, ptr
, stripped
))) goto error
;
159 ptr
= strip_spaces( ptr
);
160 if (FAILED(hr
= append_property( obj
, ptr
, stripped
))) goto error
;
161 ptr
= wcstok_s( NULL
, L
",", &ctx
);
176 static void convert_to_bstr( VARIANT
*v
)
181 if (SUCCEEDED(VariantChangeType( v
, v
, 0, VT_BSTR
))) return;
183 if (vt
== (VT_ARRAY
| VT_BSTR
))
185 unsigned int i
, count
, len
;
189 if (FAILED(SafeArrayAccessData( V_ARRAY(v
), (void **)&strings
)))
191 WINE_ERR( "Could not access array.\n" );
194 count
= V_ARRAY(v
)->rgsabound
->cElements
;
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
);
203 for (i
= 0; i
< count
; ++i
)
207 memcpy( ptr
, L
", ", 2 * sizeof(*ptr
) );
211 len
= wcslen( strings
[i
] );
212 memcpy( ptr
, strings
[i
], len
* sizeof(*ptr
) );
218 SafeArrayUnaccessData( V_ARRAY(v
) );
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
[] )
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
;
238 IWbemClassObject
*obj
;
239 ULONG count
, width
= 0;
243 WINE_TRACE( "%s", debugstr_w(class) );
244 for (i
= 0; i
< argc
; i
++) WINE_TRACE( " %s", debugstr_w(argv
[i
]) );
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
,
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
);
264 WARN("Unrecognized class %s.\n", debugstr_w(class));
268 /* Check that this class supports all requested properties. */
269 hr
= process_property_list( obj
, argc
, argv
, &proplist
);
270 IWbemClassObject_Release( obj
);
273 output_error( STRING_INVALID_QUERY
);
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
);
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
);
296 SysFreeString( name
);
299 IWbemClassObject_Release( obj
);
304 IEnumWbemClassObject_Reset( result
);
305 IEnumWbemClassObject_Next( result
, WBEM_INFINITE
, 1, &obj
, &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
);
315 IWbemClassObject_Release( obj
);
319 IEnumWbemClassObject_Reset( result
);
322 IEnumWbemClassObject_Next( result
, WBEM_INFINITE
, 1, &obj
, &count
);
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
);
332 IWbemClassObject_Release( obj
);
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
);
348 static int process_args( int argc
, WCHAR
*argv
[] )
353 for (i
= 0; i
< argc
&& argv
[i
][0] == '/'; i
++)
354 WINE_FIXME( "switch %s not supported\n", debugstr_w(argv
[i
]) );
359 if (!wcsicmp( argv
[i
], L
"quit" ) || !wcsicmp( argv
[i
], L
"exit" ))
364 if (!wcsicmp( argv
[i
], L
"class" ) || !wcsicmp( argv
[i
], L
"context" ))
366 WINE_FIXME( "command %s not supported\n", debugstr_w(argv
[i
]) );
370 if (!wcsicmp( argv
[i
], L
"path" ))
374 output_error( STRING_INVALID_PATH
);
381 class = find_class( argv
[i
] );
384 output_error( STRING_ALIAS_NOT_FOUND
);
392 if (!wcsicmp( argv
[i
], L
"get" ))
396 return query_prop( class, argc
- i
, argv
+ i
);
400 output_error( STRING_COMMAND_NOT_SUPPORTED
);
404 int __cdecl
wmain(int argc
, WCHAR
*argv
[])
406 WCHAR cmd
[MAX_STRING
];
409 setlocale( LC_ALL
, "" );
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" ))
427 output_error( STRING_USAGE
);
433 if (!(new_argv
= CommandLineToArgvW( stripped
, &new_argc
))) return 1;
434 ret
= process_args( new_argc
, new_argv
);
435 LocalFree( new_argv
);
439 fputws( L
"wmic:root\\cli>", stdout
);
444 return process_args( argc
- 1, argv
+ 1 );