Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(52)

Side by Side Diff: content/browser/geolocation/wifi_data_provider_win.cc

Issue 2192683002: Reland 2:Geolocation: move from content/browser to device/ (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Ignore size_t_to_int truncation warning Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Windows Vista uses the Native Wifi (WLAN) API for accessing WiFi cards. See
6 // http://msdn.microsoft.com/en-us/library/ms705945(VS.85).aspx. Windows XP
7 // Service Pack 3 (and Windows XP Service Pack 2, if upgraded with a hot fix)
8 // also support a limited version of the WLAN API. See
9 // http://msdn.microsoft.com/en-us/library/bb204766.aspx. The WLAN API uses
10 // wlanapi.h, which is not part of the SDK used by Gears, so is replicated
11 // locally using data from the MSDN.
12 //
13 // Windows XP from Service Pack 2 onwards supports the Wireless Zero
14 // Configuration (WZC) programming interface. See
15 // http://msdn.microsoft.com/en-us/library/ms706587(VS.85).aspx.
16 //
17 // The MSDN recommends that one use the WLAN API where available, and WZC
18 // otherwise.
19 //
20 // However, it seems that WZC fails for some wireless cards. Also, WLAN seems
21 // not to work on XP SP3. So we use WLAN on Vista, and use NDIS directly
22 // otherwise.
23
24 #include "content/browser/geolocation/wifi_data_provider_win.h"
25
26 #include <windows.h>
27 #include <winioctl.h>
28 #include <wlanapi.h>
29
30 #include "base/memory/free_deleter.h"
31 #include "base/metrics/histogram.h"
32 #include "base/strings/utf_string_conversions.h"
33 #include "base/win/windows_version.h"
34 #include "content/browser/geolocation/wifi_data_provider_common.h"
35 #include "content/browser/geolocation/wifi_data_provider_common_win.h"
36 #include "content/browser/geolocation/wifi_data_provider_manager.h"
37
38 // Taken from ndis.h for WinCE.
39 #define NDIS_STATUS_INVALID_LENGTH ((NDIS_STATUS)0xC0010014L)
40 #define NDIS_STATUS_BUFFER_TOO_SHORT ((NDIS_STATUS)0xC0010016L)
41
42 namespace content {
43 namespace {
44 // The limits on the size of the buffer used for the OID query.
45 const int kInitialBufferSize = 2 << 12; // Good for about 50 APs.
46 const int kMaximumBufferSize = 2 << 20; // 2MB
47
48 // Length for generic string buffers passed to Windows APIs.
49 const int kStringLength = 512;
50
51 // The time periods, in milliseconds, between successive polls of the wifi data.
52 const int kDefaultPollingInterval = 10000; // 10s
53 const int kNoChangePollingInterval = 120000; // 2 mins
54 const int kTwoNoChangePollingInterval = 600000; // 10 mins
55 const int kNoWifiPollingIntervalMilliseconds = 20 * 1000; // 20s
56
57 // WlanOpenHandle
58 typedef DWORD (WINAPI* WlanOpenHandleFunction)(DWORD dwClientVersion,
59 PVOID pReserved,
60 PDWORD pdwNegotiatedVersion,
61 PHANDLE phClientHandle);
62
63 // WlanEnumInterfaces
64 typedef DWORD (WINAPI* WlanEnumInterfacesFunction)(
65 HANDLE hClientHandle,
66 PVOID pReserved,
67 PWLAN_INTERFACE_INFO_LIST* ppInterfaceList);
68
69 // WlanGetNetworkBssList
70 typedef DWORD (WINAPI* WlanGetNetworkBssListFunction)(
71 HANDLE hClientHandle,
72 const GUID* pInterfaceGuid,
73 const PDOT11_SSID pDot11Ssid,
74 DOT11_BSS_TYPE dot11BssType,
75 BOOL bSecurityEnabled,
76 PVOID pReserved,
77 PWLAN_BSS_LIST* ppWlanBssList
78 );
79
80 // WlanFreeMemory
81 typedef VOID (WINAPI* WlanFreeMemoryFunction)(PVOID pMemory);
82
83 // WlanCloseHandle
84 typedef DWORD (WINAPI* WlanCloseHandleFunction)(HANDLE hClientHandle,
85 PVOID pReserved);
86
87
88 // Local classes and functions
89 class WindowsWlanApi : public WifiDataProviderCommon::WlanApiInterface {
90 public:
91 ~WindowsWlanApi() override;
92 // Factory function. Will return NULL if this API is unavailable.
93 static WindowsWlanApi* Create();
94
95 // WlanApiInterface
96 bool GetAccessPointData(WifiData::AccessPointDataSet* data) override;
97
98 private:
99 // Takes ownership of the library handle.
100 explicit WindowsWlanApi(HINSTANCE library);
101
102 // Loads the required functions from the DLL.
103 void GetWLANFunctions(HINSTANCE wlan_library);
104 int GetInterfaceDataWLAN(HANDLE wlan_handle,
105 const GUID& interface_id,
106 WifiData::AccessPointDataSet* data);
107
108 // Logs number of detected wlan interfaces.
109 static void LogWlanInterfaceCount(int count);
110
111 // Handle to the wlanapi.dll library.
112 HINSTANCE library_;
113
114 // Function pointers for WLAN
115 WlanOpenHandleFunction WlanOpenHandle_function_;
116 WlanEnumInterfacesFunction WlanEnumInterfaces_function_;
117 WlanGetNetworkBssListFunction WlanGetNetworkBssList_function_;
118 WlanFreeMemoryFunction WlanFreeMemory_function_;
119 WlanCloseHandleFunction WlanCloseHandle_function_;
120 };
121
122 class WindowsNdisApi : public WifiDataProviderCommon::WlanApiInterface {
123 public:
124 ~WindowsNdisApi() override;
125 static WindowsNdisApi* Create();
126
127 // WlanApiInterface
128 bool GetAccessPointData(WifiData::AccessPointDataSet* data) override;
129
130 private:
131 static bool GetInterfacesNDIS(
132 std::vector<base::string16>* interface_service_names_out);
133
134 // Swaps in content of the vector passed
135 explicit WindowsNdisApi(std::vector<base::string16>* interface_service_names);
136
137 bool GetInterfaceDataNDIS(HANDLE adapter_handle,
138 WifiData::AccessPointDataSet* data);
139 // NDIS variables.
140 std::vector<base::string16> interface_service_names_;
141
142 // Remembers scan result buffer size across calls.
143 int oid_buffer_size_;
144 };
145
146 // Extracts data for an access point and converts to Gears format.
147 bool GetNetworkData(const WLAN_BSS_ENTRY& bss_entry,
148 AccessPointData* access_point_data);
149 bool UndefineDosDevice(const base::string16& device_name);
150 bool DefineDosDeviceIfNotExists(const base::string16& device_name);
151 HANDLE GetFileHandle(const base::string16& device_name);
152 // Makes the OID query and returns a Windows API error code.
153 int PerformQuery(HANDLE adapter_handle,
154 BYTE* buffer,
155 DWORD buffer_size,
156 DWORD* bytes_out);
157 bool ResizeBuffer(int requested_size,
158 std::unique_ptr<BYTE, base::FreeDeleter>* buffer);
159 // Gets the system directory and appends a trailing slash if not already
160 // present.
161 bool GetSystemDirectory(base::string16* path);
162 } // namespace
163
164 WifiDataProvider* WifiDataProviderManager::DefaultFactoryFunction() {
165 return new WifiDataProviderWin();
166 }
167
168 WifiDataProviderWin::WifiDataProviderWin() {
169 }
170
171 WifiDataProviderWin::~WifiDataProviderWin() {
172 }
173
174 WifiDataProviderCommon::WlanApiInterface* WifiDataProviderWin::NewWlanApi() {
175 // Use the WLAN interface if we're on Vista and if it's available. Otherwise,
176 // use NDIS.
177 WlanApiInterface* api = WindowsWlanApi::Create();
178 if (api) {
179 return api;
180 }
181 return WindowsNdisApi::Create();
182 }
183
184 WifiPollingPolicy* WifiDataProviderWin::NewPollingPolicy() {
185 return new GenericWifiPollingPolicy<kDefaultPollingInterval,
186 kNoChangePollingInterval,
187 kTwoNoChangePollingInterval,
188 kNoWifiPollingIntervalMilliseconds>;
189 }
190
191 // Local classes and functions
192 namespace {
193
194 // WindowsWlanApi
195 WindowsWlanApi::WindowsWlanApi(HINSTANCE library)
196 : library_(library) {
197 GetWLANFunctions(library_);
198 }
199
200 WindowsWlanApi::~WindowsWlanApi() {
201 FreeLibrary(library_);
202 }
203
204 WindowsWlanApi* WindowsWlanApi::Create() {
205 if (base::win::GetVersion() < base::win::VERSION_VISTA)
206 return NULL;
207 // We use an absolute path to load the DLL to avoid DLL preloading attacks.
208 base::string16 system_directory;
209 if (!GetSystemDirectory(&system_directory)) {
210 return NULL;
211 }
212 DCHECK(!system_directory.empty());
213 base::string16 dll_path = system_directory + L"wlanapi.dll";
214 HINSTANCE library = LoadLibraryEx(dll_path.c_str(),
215 NULL,
216 LOAD_WITH_ALTERED_SEARCH_PATH);
217 if (!library) {
218 return NULL;
219 }
220 return new WindowsWlanApi(library);
221 }
222
223 void WindowsWlanApi::GetWLANFunctions(HINSTANCE wlan_library) {
224 DCHECK(wlan_library);
225 WlanOpenHandle_function_ = reinterpret_cast<WlanOpenHandleFunction>(
226 GetProcAddress(wlan_library, "WlanOpenHandle"));
227 WlanEnumInterfaces_function_ = reinterpret_cast<WlanEnumInterfacesFunction>(
228 GetProcAddress(wlan_library, "WlanEnumInterfaces"));
229 WlanGetNetworkBssList_function_ =
230 reinterpret_cast<WlanGetNetworkBssListFunction>(
231 GetProcAddress(wlan_library, "WlanGetNetworkBssList"));
232 WlanFreeMemory_function_ = reinterpret_cast<WlanFreeMemoryFunction>(
233 GetProcAddress(wlan_library, "WlanFreeMemory"));
234 WlanCloseHandle_function_ = reinterpret_cast<WlanCloseHandleFunction>(
235 GetProcAddress(wlan_library, "WlanCloseHandle"));
236 DCHECK(WlanOpenHandle_function_ &&
237 WlanEnumInterfaces_function_ &&
238 WlanGetNetworkBssList_function_ &&
239 WlanFreeMemory_function_ &&
240 WlanCloseHandle_function_);
241 }
242
243 void WindowsWlanApi::LogWlanInterfaceCount(int count) {
244 UMA_HISTOGRAM_CUSTOM_COUNTS(
245 "Net.Wifi.InterfaceCount",
246 count,
247 1,
248 5,
249 6);
250 }
251
252 bool WindowsWlanApi::GetAccessPointData(
253 WifiData::AccessPointDataSet* data) {
254 DCHECK(data);
255
256 // Get the handle to the WLAN API.
257 DWORD negotiated_version;
258 HANDLE wlan_handle = NULL;
259 // We could be executing on either Windows XP or Windows Vista, so use the
260 // lower version of the client WLAN API. It seems that the negotiated version
261 // is the Vista version irrespective of what we pass!
262 static const int kXpWlanClientVersion = 1;
263 if ((*WlanOpenHandle_function_)(kXpWlanClientVersion,
264 NULL,
265 &negotiated_version,
266 &wlan_handle) != ERROR_SUCCESS) {
267 LogWlanInterfaceCount(0);
268 return false;
269 }
270 DCHECK(wlan_handle);
271
272 // Get the list of interfaces. WlanEnumInterfaces allocates interface_list.
273 WLAN_INTERFACE_INFO_LIST* interface_list = NULL;
274 if ((*WlanEnumInterfaces_function_)(wlan_handle, NULL, &interface_list) !=
275 ERROR_SUCCESS) {
276 LogWlanInterfaceCount(0);
277 return false;
278 }
279 DCHECK(interface_list);
280
281 LogWlanInterfaceCount(interface_list->dwNumberOfItems);
282
283 // Go through the list of interfaces and get the data for each.
284 for (int i = 0; i < static_cast<int>(interface_list->dwNumberOfItems); ++i) {
285 // Skip any interface that is midway through association; the
286 // WlanGetNetworkBssList function call is known to hang indefinitely
287 // when it's in this state. http://crbug.com/39300
288 if (interface_list->InterfaceInfo[i].isState ==
289 wlan_interface_state_associating) {
290 LOG(WARNING) << "Skipping wifi scan on adapter " << i << " ("
291 << interface_list->InterfaceInfo[i].strInterfaceDescription
292 << ") in 'associating' state. Repeated occurrences "
293 "indicates a non-responding adapter.";
294 continue;
295 }
296 GetInterfaceDataWLAN(wlan_handle,
297 interface_list->InterfaceInfo[i].InterfaceGuid,
298 data);
299 }
300
301 // Free interface_list.
302 (*WlanFreeMemory_function_)(interface_list);
303
304 // Close the handle.
305 if ((*WlanCloseHandle_function_)(wlan_handle, NULL) != ERROR_SUCCESS) {
306 return false;
307 }
308
309 return true;
310 }
311
312 // Appends the data for a single interface to the data vector. Returns the
313 // number of access points found, or -1 on error.
314 int WindowsWlanApi::GetInterfaceDataWLAN(
315 const HANDLE wlan_handle,
316 const GUID& interface_id,
317 WifiData::AccessPointDataSet* data) {
318 DCHECK(data);
319
320 const base::TimeTicks start_time = base::TimeTicks::Now();
321
322 // WlanGetNetworkBssList allocates bss_list.
323 WLAN_BSS_LIST* bss_list = NULL;
324 if ((*WlanGetNetworkBssList_function_)(wlan_handle,
325 &interface_id,
326 NULL, // Use all SSIDs.
327 dot11_BSS_type_any,
328 false, // bSecurityEnabled - unused
329 NULL, // reserved
330 &bss_list) != ERROR_SUCCESS) {
331 return -1;
332 }
333 // According to http://www.attnetclient.com/kb/questions.php?questionid=75
334 // WlanGetNetworkBssList can sometimes return success, but leave the bss
335 // list as NULL.
336 if (!bss_list)
337 return -1;
338
339 const base::TimeDelta duration = base::TimeTicks::Now() - start_time;
340
341 UMA_HISTOGRAM_CUSTOM_TIMES(
342 "Net.Wifi.ScanLatency",
343 duration,
344 base::TimeDelta::FromMilliseconds(1),
345 base::TimeDelta::FromMinutes(1),
346 100);
347
348
349 int found = 0;
350 for (int i = 0; i < static_cast<int>(bss_list->dwNumberOfItems); ++i) {
351 AccessPointData access_point_data;
352 if (GetNetworkData(bss_list->wlanBssEntries[i], &access_point_data)) {
353 ++found;
354 data->insert(access_point_data);
355 }
356 }
357
358 (*WlanFreeMemory_function_)(bss_list);
359
360 return found;
361 }
362
363 // WindowsNdisApi
364 WindowsNdisApi::WindowsNdisApi(
365 std::vector<base::string16>* interface_service_names)
366 : oid_buffer_size_(kInitialBufferSize) {
367 DCHECK(!interface_service_names->empty());
368 interface_service_names_.swap(*interface_service_names);
369 }
370
371 WindowsNdisApi::~WindowsNdisApi() {
372 }
373
374 WindowsNdisApi* WindowsNdisApi::Create() {
375 std::vector<base::string16> interface_service_names;
376 if (GetInterfacesNDIS(&interface_service_names)) {
377 return new WindowsNdisApi(&interface_service_names);
378 }
379 return NULL;
380 }
381
382 bool WindowsNdisApi::GetAccessPointData(WifiData::AccessPointDataSet* data) {
383 DCHECK(data);
384 int interfaces_failed = 0;
385 int interfaces_succeeded = 0;
386
387 for (int i = 0; i < static_cast<int>(interface_service_names_.size()); ++i) {
388 // First, check that we have a DOS device for this adapter.
389 if (!DefineDosDeviceIfNotExists(interface_service_names_[i])) {
390 continue;
391 }
392
393 // Get the handle to the device. This will fail if the named device is not
394 // valid.
395 HANDLE adapter_handle = GetFileHandle(interface_service_names_[i]);
396 if (adapter_handle == INVALID_HANDLE_VALUE) {
397 continue;
398 }
399
400 // Get the data.
401 if (GetInterfaceDataNDIS(adapter_handle, data)) {
402 ++interfaces_succeeded;
403 } else {
404 ++interfaces_failed;
405 }
406
407 // Clean up.
408 CloseHandle(adapter_handle);
409 UndefineDosDevice(interface_service_names_[i]);
410 }
411
412 // Return true if at least one interface succeeded, or at the very least none
413 // failed.
414 return interfaces_succeeded > 0 || interfaces_failed == 0;
415 }
416
417 bool WindowsNdisApi::GetInterfacesNDIS(
418 std::vector<base::string16>* interface_service_names_out) {
419 HKEY network_cards_key = NULL;
420 if (RegOpenKeyEx(
421 HKEY_LOCAL_MACHINE,
422 L"Software\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards",
423 0,
424 KEY_READ,
425 &network_cards_key) != ERROR_SUCCESS) {
426 return false;
427 }
428 DCHECK(network_cards_key);
429
430 for (int i = 0; ; ++i) {
431 TCHAR name[kStringLength];
432 DWORD name_size = kStringLength;
433 FILETIME time;
434 if (RegEnumKeyEx(network_cards_key,
435 i,
436 name,
437 &name_size,
438 NULL,
439 NULL,
440 NULL,
441 &time) != ERROR_SUCCESS) {
442 break;
443 }
444 HKEY hardware_key = NULL;
445 if (RegOpenKeyEx(network_cards_key, name, 0, KEY_READ, &hardware_key) !=
446 ERROR_SUCCESS) {
447 break;
448 }
449 DCHECK(hardware_key);
450
451 TCHAR service_name[kStringLength];
452 DWORD service_name_size = kStringLength;
453 DWORD type = 0;
454 if (RegQueryValueEx(hardware_key,
455 L"ServiceName",
456 NULL,
457 &type,
458 reinterpret_cast<LPBYTE>(service_name),
459 &service_name_size) == ERROR_SUCCESS) {
460 interface_service_names_out->push_back(service_name);
461 }
462 RegCloseKey(hardware_key);
463 }
464
465 RegCloseKey(network_cards_key);
466 return true;
467 }
468
469
470 bool WindowsNdisApi::GetInterfaceDataNDIS(HANDLE adapter_handle,
471 WifiData::AccessPointDataSet* data) {
472 DCHECK(data);
473
474 std::unique_ptr<BYTE, base::FreeDeleter> buffer(
475 static_cast<BYTE*>(malloc(oid_buffer_size_)));
476 if (buffer == NULL) {
477 return false;
478 }
479
480 DWORD bytes_out;
481 int result;
482
483 while (true) {
484 bytes_out = 0;
485 result = PerformQuery(adapter_handle, buffer.get(),
486 oid_buffer_size_, &bytes_out);
487 if (result == ERROR_GEN_FAILURE || // Returned by some Intel cards.
488 result == ERROR_INSUFFICIENT_BUFFER ||
489 result == ERROR_MORE_DATA ||
490 result == NDIS_STATUS_INVALID_LENGTH ||
491 result == NDIS_STATUS_BUFFER_TOO_SHORT) {
492 // The buffer we supplied is too small, so increase it. bytes_out should
493 // provide the required buffer size, but this is not always the case.
494 if (bytes_out > static_cast<DWORD>(oid_buffer_size_)) {
495 oid_buffer_size_ = bytes_out;
496 } else {
497 oid_buffer_size_ *= 2;
498 }
499 if (!ResizeBuffer(oid_buffer_size_, &buffer)) {
500 oid_buffer_size_ = kInitialBufferSize; // Reset for next time.
501 return false;
502 }
503 } else {
504 // The buffer is not too small.
505 break;
506 }
507 }
508 DCHECK(buffer.get());
509
510 if (result == ERROR_SUCCESS) {
511 NDIS_802_11_BSSID_LIST* bssid_list =
512 reinterpret_cast<NDIS_802_11_BSSID_LIST*>(buffer.get());
513 GetDataFromBssIdList(*bssid_list, oid_buffer_size_, data);
514 }
515
516 return true;
517 }
518
519 bool GetNetworkData(const WLAN_BSS_ENTRY& bss_entry,
520 AccessPointData* access_point_data) {
521 // Currently we get only MAC address, signal strength and SSID.
522 DCHECK(access_point_data);
523 access_point_data->mac_address = MacAddressAsString16(bss_entry.dot11Bssid);
524 access_point_data->radio_signal_strength = bss_entry.lRssi;
525 // bss_entry.dot11Ssid.ucSSID is not null-terminated.
526 base::UTF8ToUTF16(reinterpret_cast<const char*>(bss_entry.dot11Ssid.ucSSID),
527 static_cast<ULONG>(bss_entry.dot11Ssid.uSSIDLength),
528 &access_point_data->ssid);
529 // TODO(steveblock): Is it possible to get the following?
530 // access_point_data->signal_to_noise
531 // access_point_data->age
532 // access_point_data->channel
533 return true;
534 }
535
536 bool UndefineDosDevice(const base::string16& device_name) {
537 // We remove only the mapping we use, that is \Device\<device_name>.
538 base::string16 target_path = L"\\Device\\" + device_name;
539 return DefineDosDevice(
540 DDD_RAW_TARGET_PATH | DDD_REMOVE_DEFINITION | DDD_EXACT_MATCH_ON_REMOVE,
541 device_name.c_str(),
542 target_path.c_str()) == TRUE;
543 }
544
545 bool DefineDosDeviceIfNotExists(const base::string16& device_name) {
546 // We create a DOS device name for the device at \Device\<device_name>.
547 base::string16 target_path = L"\\Device\\" + device_name;
548
549 TCHAR target[kStringLength];
550 if (QueryDosDevice(device_name.c_str(), target, kStringLength) > 0 &&
551 target_path.compare(target) == 0) {
552 // Device already exists.
553 return true;
554 }
555
556 if (GetLastError() != ERROR_FILE_NOT_FOUND) {
557 return false;
558 }
559
560 if (!DefineDosDevice(DDD_RAW_TARGET_PATH,
561 device_name.c_str(),
562 target_path.c_str())) {
563 return false;
564 }
565
566 // Check that the device is really there.
567 return QueryDosDevice(device_name.c_str(), target, kStringLength) > 0 &&
568 target_path.compare(target) == 0;
569 }
570
571 HANDLE GetFileHandle(const base::string16& device_name) {
572 // We access a device with DOS path \Device\<device_name> at
573 // \\.\<device_name>.
574 base::string16 formatted_device_name = L"\\\\.\\" + device_name;
575
576 return CreateFile(formatted_device_name.c_str(),
577 GENERIC_READ,
578 FILE_SHARE_READ | FILE_SHARE_WRITE, // share mode
579 0, // security attributes
580 OPEN_EXISTING,
581 0, // flags and attributes
582 INVALID_HANDLE_VALUE);
583 }
584
585 int PerformQuery(HANDLE adapter_handle,
586 BYTE* buffer,
587 DWORD buffer_size,
588 DWORD* bytes_out) {
589 DWORD oid = OID_802_11_BSSID_LIST;
590 if (!DeviceIoControl(adapter_handle,
591 IOCTL_NDIS_QUERY_GLOBAL_STATS,
592 &oid,
593 sizeof(oid),
594 buffer,
595 buffer_size,
596 bytes_out,
597 NULL)) {
598 return GetLastError();
599 }
600 return ERROR_SUCCESS;
601 }
602
603 bool ResizeBuffer(int requested_size,
604 std::unique_ptr<BYTE, base::FreeDeleter>* buffer) {
605 DCHECK_GT(requested_size, 0);
606 DCHECK(buffer);
607 if (requested_size > kMaximumBufferSize) {
608 buffer->reset();
609 return false;
610 }
611
612 buffer->reset(reinterpret_cast<BYTE*>(
613 realloc(buffer->release(), requested_size)));
614 return buffer != NULL;
615 }
616
617 bool GetSystemDirectory(base::string16* path) {
618 DCHECK(path);
619 // Return value includes terminating NULL.
620 int buffer_size = ::GetSystemDirectory(NULL, 0);
621 if (buffer_size == 0) {
622 return false;
623 }
624 std::unique_ptr<base::char16[]> buffer(new base::char16[buffer_size]);
625
626 // Return value excludes terminating NULL.
627 int characters_written = ::GetSystemDirectory(buffer.get(), buffer_size);
628 if (characters_written == 0) {
629 return false;
630 }
631 DCHECK_EQ(buffer_size - 1, characters_written);
632
633 path->assign(buffer.get(), characters_written);
634
635 if (*path->rbegin() != L'\\') {
636 path->append(L"\\");
637 }
638 DCHECK_EQ(L'\\', *path->rbegin());
639 return true;
640 }
641 } // namespace
642
643 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/geolocation/wifi_data_provider_win.h ('k') | content/browser/geolocation/wifi_data_provider_win_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698