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
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(wmic
);
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
)
61 for (i
= 0; i
< ARRAY_SIZE(alias_map
); i
++)
63 if (!wcsicmp( alias
, alias_map
[i
].alias
)) return alias_map
[i
].class;
68 static int WINAPIV
output_string( const WCHAR
*msg
, ... )
70 int count
, bom_count
= 0;
76 if (GetFileType((HANDLE
)_get_osfhandle( STDOUT_FILENO
)) == FILE_TYPE_DISK
)
78 _setmode( STDOUT_FILENO
, _O_U16TEXT
);
79 bom_count
= wprintf( L
"\xfeff" );
84 va_start( va_args
, msg
);
85 count
= vwprintf( msg
, va_args
);
87 return count
+ bom_count
;
90 static int output_error( int msg
)
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
;
115 end
= start
+ lstrlenW(start
) - 1;
116 while (end
>= start
&& *end
== ' ')
125 static HRESULT
process_property_list( IWbemClassObject
*obj
, const WCHAR
*proplist
, WCHAR
**ret
)
127 WCHAR
*p
, *ctx
, *ptr
, *stripped
;
130 if (!(p
= wcsdup( proplist
))) return E_OUTOFMEMORY
;
132 if (!(stripped
= malloc( (wcslen( proplist
) + 1) * sizeof(**ret
) )))
135 return E_OUTOFMEMORY
;
139 /* Validate that every requested property is supported. */
140 ptr
= wcstok_s( p
, L
",", &ctx
);
143 ptr
= strip_spaces( ptr
);
145 if (FAILED(IWbemClassObject_Get( obj
, ptr
, 0, NULL
, NULL
, NULL
)))
150 if (*stripped
) wcscat( stripped
, L
"," );
151 wcscat( stripped
, ptr
);
152 ptr
= wcstok_s( NULL
, L
",", &ctx
);
167 static void convert_to_bstr( VARIANT
*v
)
172 if (SUCCEEDED(VariantChangeType( v
, v
, 0, VT_BSTR
))) return;
174 if (vt
== (VT_ARRAY
| VT_BSTR
))
176 unsigned int i
, count
, len
;
180 if (FAILED(SafeArrayAccessData( V_ARRAY(v
), (void **)&strings
)))
182 WINE_ERR( "Could not access array.\n" );
185 count
= V_ARRAY(v
)->rgsabound
->cElements
;
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
);
194 for (i
= 0; i
< count
; ++i
)
198 memcpy( ptr
, L
", ", 2 * sizeof(*ptr
) );
202 len
= wcslen( strings
[i
] );
203 memcpy( ptr
, strings
[i
], len
* sizeof(*ptr
) );
209 SafeArrayUnaccessData( V_ARRAY(v
) );
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
)
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
;
229 IWbemClassObject
*obj
;
230 ULONG count
, width
= 0;
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
,
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
);
252 WARN("Unrecognized class %s.\n", debugstr_w(class));
256 /* Check that this class supports all requested properties. */
257 hr
= process_property_list( obj
, propnames
, &proplist
);
258 IWbemClassObject_Release( obj
);
261 output_error( STRING_INVALID_QUERY
);
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
);
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
);
284 SysFreeString( name
);
287 IWbemClassObject_Release( obj
);
292 IEnumWbemClassObject_Reset( result
);
293 IEnumWbemClassObject_Next( result
, WBEM_INFINITE
, 1, &obj
, &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
);
303 IWbemClassObject_Release( obj
);
307 IEnumWbemClassObject_Reset( result
);
310 IEnumWbemClassObject_Next( result
, WBEM_INFINITE
, 1, &obj
, &count
);
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
);
320 IWbemClassObject_Release( obj
);
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
);
336 int __cdecl
wmain(int argc
, WCHAR
*argv
[])
338 const WCHAR
*class, *value
;
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
]) );
349 if (!wcsicmp( argv
[i
], L
"quit" ) || !wcsicmp( argv
[i
], L
"exit" ))
354 if (!wcsicmp( argv
[i
], L
"class") || !wcsicmp( argv
[i
], L
"context" ))
356 WINE_FIXME( "command %s not supported\n", debugstr_w(argv
[i
]) );
360 if (!wcsicmp( argv
[i
], L
"path" ))
364 output_error( STRING_INVALID_PATH
);
371 class = find_class( argv
[i
] );
374 output_error( STRING_ALIAS_NOT_FOUND
);
382 if (!wcsicmp( argv
[i
], L
"get" ))
387 return query_prop( class, value
);
391 output_error( STRING_CMDLINE_NOT_SUPPORTED
);