1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #ifdef WIN32
18
19 #include "apr.h"
20 #include "arch/win32/apr_arch_file_io.h"
21 #include "arch/win32/apr_arch_misc.h"
22 #include "ap_regkey.h"
23
24 struct ap_regkey_t {
25 apr_pool_t *pool;
26 HKEY hkey;
27 };
28
29
ap_regkey_const(int i)30 AP_DECLARE(const ap_regkey_t *) ap_regkey_const(int i)
31 {
32 static struct ap_regkey_t ap_regkey_consts[7] =
33 {
34 {NULL, HKEY_CLASSES_ROOT},
35 {NULL, HKEY_CURRENT_CONFIG},
36 {NULL, HKEY_CURRENT_USER},
37 {NULL, HKEY_LOCAL_MACHINE},
38 {NULL, HKEY_USERS},
39 {NULL, HKEY_PERFORMANCE_DATA},
40 {NULL, HKEY_DYN_DATA}
41 };
42 return ap_regkey_consts + i;
43 }
44
45
regkey_cleanup(void * key)46 static apr_status_t regkey_cleanup(void *key)
47 {
48 ap_regkey_t *regkey = key;
49
50 if (regkey->hkey && regkey->hkey != INVALID_HANDLE_VALUE) {
51 RegCloseKey(regkey->hkey);
52 regkey->hkey = INVALID_HANDLE_VALUE;
53 }
54 return APR_SUCCESS;
55 }
56
57
ap_regkey_open(ap_regkey_t ** newkey,const ap_regkey_t * parentkey,const char * keyname,apr_int32_t flags,apr_pool_t * pool)58 AP_DECLARE(apr_status_t) ap_regkey_open(ap_regkey_t **newkey,
59 const ap_regkey_t *parentkey,
60 const char *keyname,
61 apr_int32_t flags,
62 apr_pool_t *pool)
63 {
64 DWORD access = KEY_QUERY_VALUE;
65 DWORD exists;
66 HKEY hkey;
67 LONG rc;
68
69 if (flags & APR_READ)
70 access |= KEY_READ;
71 if (flags & APR_WRITE)
72 access |= KEY_WRITE;
73
74 #if APR_HAS_UNICODE_FS
75 IF_WIN_OS_IS_UNICODE
76 {
77 apr_size_t keylen = strlen(keyname) + 1;
78 apr_size_t wkeylen = 256;
79 apr_wchar_t wkeyname[256];
80 apr_status_t rv = apr_conv_utf8_to_ucs2(keyname, &keylen, wkeyname, &wkeylen);
81 if (rv != APR_SUCCESS)
82 return rv;
83 else if (keylen)
84 return APR_ENAMETOOLONG;
85
86 if (flags & APR_CREATE)
87 rc = RegCreateKeyExW(parentkey->hkey, wkeyname, 0, NULL, 0,
88 access, NULL, &hkey, &exists);
89 else
90 rc = RegOpenKeyExW(parentkey->hkey, wkeyname, 0, access, &hkey);
91 }
92 #endif /* APR_HAS_UNICODE_FS */
93 #if APR_HAS_ANSI_FS
94 ELSE_WIN_OS_IS_ANSI
95 {
96 if (flags & APR_CREATE)
97 rc = RegCreateKeyEx(parentkey->hkey, keyname, 0, NULL, 0,
98 access, NULL, &hkey, &exists);
99 else
100 rc = RegOpenKeyEx(parentkey->hkey, keyname, 0, access, &hkey);
101 }
102 #endif
103 if (rc != ERROR_SUCCESS) {
104 return APR_FROM_OS_ERROR(rc);
105 }
106 if ((flags & APR_EXCL) && (exists == REG_OPENED_EXISTING_KEY)) {
107 RegCloseKey(hkey);
108 return APR_EEXIST;
109 }
110
111 *newkey = apr_palloc(pool, sizeof(**newkey));
112 (*newkey)->pool = pool;
113 (*newkey)->hkey = hkey;
114 apr_pool_cleanup_register((*newkey)->pool, (void *)(*newkey),
115 regkey_cleanup, apr_pool_cleanup_null);
116 return APR_SUCCESS;
117 }
118
119
ap_regkey_close(ap_regkey_t * regkey)120 AP_DECLARE(apr_status_t) ap_regkey_close(ap_regkey_t *regkey)
121 {
122 apr_status_t stat;
123 if ((stat = regkey_cleanup(regkey)) == APR_SUCCESS) {
124 apr_pool_cleanup_kill(regkey->pool, regkey, regkey_cleanup);
125 }
126 return stat;
127 }
128
129
ap_regkey_remove(const ap_regkey_t * parent,const char * keyname,apr_pool_t * pool)130 AP_DECLARE(apr_status_t) ap_regkey_remove(const ap_regkey_t *parent,
131 const char *keyname,
132 apr_pool_t *pool)
133 {
134 LONG rc;
135
136 #if APR_HAS_UNICODE_FS
137 IF_WIN_OS_IS_UNICODE
138 {
139 apr_size_t keylen = strlen(keyname) + 1;
140 apr_size_t wkeylen = 256;
141 apr_wchar_t wkeyname[256];
142 apr_status_t rv = apr_conv_utf8_to_ucs2(keyname, &keylen, wkeyname, &wkeylen);
143 if (rv != APR_SUCCESS)
144 return rv;
145 else if (keylen)
146 return APR_ENAMETOOLONG;
147 rc = RegDeleteKeyW(parent->hkey, wkeyname);
148 }
149 #endif /* APR_HAS_UNICODE_FS */
150 #if APR_HAS_ANSI_FS
151 ELSE_WIN_OS_IS_ANSI
152 {
153 /* We need to determine if subkeys exist on Win9x, to provide
154 * consistent behavior with NT, which returns access denied
155 * if subkeys exist when attempting to delete a key.
156 */
157 DWORD subkeys;
158 HKEY hkey;
159 rc = RegOpenKeyEx(parent->hkey, keyname, 0, KEY_READ, &hkey);
160 if (rc != ERROR_SUCCESS)
161 return APR_FROM_OS_ERROR(rc);
162 rc = RegQueryInfoKey(hkey, NULL, NULL, NULL, &subkeys, NULL, NULL,
163 NULL, NULL, NULL, NULL, NULL);
164 RegCloseKey(hkey);
165 if (rc != ERROR_SUCCESS)
166 return APR_FROM_OS_ERROR(rc);
167 else if (subkeys)
168 return APR_FROM_OS_ERROR(ERROR_ACCESS_DENIED);
169 rc = RegDeleteKey(parent->hkey, keyname);
170 }
171 #endif
172 if (rc != ERROR_SUCCESS) {
173 return APR_FROM_OS_ERROR(rc);
174 }
175 return APR_SUCCESS;
176 }
177
178
ap_regkey_value_get(char ** result,ap_regkey_t * key,const char * valuename,apr_pool_t * pool)179 AP_DECLARE(apr_status_t) ap_regkey_value_get(char **result,
180 ap_regkey_t *key,
181 const char *valuename,
182 apr_pool_t *pool)
183 {
184 /* Retrieve a registry string value, and explode any envvars
185 * that the system has configured (e.g. %SystemRoot%/someapp.exe)
186 */
187 LONG rc;
188 DWORD type;
189 apr_size_t size = 0;
190
191 #if APR_HAS_UNICODE_FS
192 IF_WIN_OS_IS_UNICODE
193 {
194 apr_size_t valuelen = strlen(valuename) + 1;
195 apr_size_t wvallen = 256;
196 apr_wchar_t wvalname[256];
197 apr_wchar_t *wvalue;
198 apr_status_t rv;
199 rv = apr_conv_utf8_to_ucs2(valuename, &valuelen, wvalname, &wvallen);
200 if (rv != APR_SUCCESS)
201 return rv;
202 else if (valuelen)
203 return APR_ENAMETOOLONG;
204 /* Read to NULL buffer to determine value size */
205 rc = RegQueryValueExW(key->hkey, wvalname, 0, &type, NULL, (DWORD *)&size);
206 if (rc != ERROR_SUCCESS) {
207 return APR_FROM_OS_ERROR(rc);
208 }
209 if ((size < 2) || (type != REG_SZ && type != REG_EXPAND_SZ)) {
210 return APR_FROM_OS_ERROR(ERROR_INVALID_PARAMETER);
211 }
212
213 wvalue = apr_palloc(pool, size);
214 /* Read value based on size query above */
215 rc = RegQueryValueExW(key->hkey, wvalname, 0, &type,
216 (LPBYTE)wvalue, (DWORD *)&size);
217 if (rc != ERROR_SUCCESS) {
218 return APR_FROM_OS_ERROR(rc);
219 }
220 if (type == REG_EXPAND_SZ) {
221 apr_wchar_t zbuf[1];
222 size = ExpandEnvironmentStringsW(wvalue, zbuf, 0);
223 if (size) {
224 apr_wchar_t *tmp = wvalue;
225 /* The size returned by ExpandEnvironmentStringsW is wchars */
226 wvalue = apr_palloc(pool, size * 2);
227 size = ExpandEnvironmentStringsW(tmp, wvalue, (DWORD)size);
228 }
229 }
230 else {
231 /* count wchars from RegQueryValueExW, rather than bytes */
232 size /= 2;
233 }
234 /* ###: deliberately overallocate all but the trailing null.
235 * We could precalculate the exact buffer here instead, the question
236 * is a matter of storage v.s. cpu cycles.
237 */
238 valuelen = (size - 1) * 3 + 1;
239 *result = apr_palloc(pool, valuelen);
240 rv = apr_conv_ucs2_to_utf8(wvalue, &size, *result, &valuelen);
241 if (rv != APR_SUCCESS)
242 return rv;
243 else if (size)
244 return APR_ENAMETOOLONG;
245 }
246 #endif /* APR_HAS_UNICODE_FS */
247 #if APR_HAS_ANSI_FS
248 ELSE_WIN_OS_IS_ANSI
249 {
250 /* Read to NULL buffer to determine value size */
251 rc = RegQueryValueEx(key->hkey, valuename, 0, &type, NULL, (DWORD *)&size);
252 if (rc != ERROR_SUCCESS)
253 return APR_FROM_OS_ERROR(rc);
254
255 if ((size < 1) || (type != REG_SZ && type != REG_EXPAND_SZ)) {
256 return APR_FROM_OS_ERROR(ERROR_INVALID_PARAMETER);
257 }
258
259 *result = apr_palloc(pool, size);
260 /* Read value based on size query above */
261 rc = RegQueryValueEx(key->hkey, valuename, 0, &type, *result, (DWORD *)&size);
262 if (rc != ERROR_SUCCESS)
263 return APR_FROM_OS_ERROR(rc);
264
265 if (type == REG_EXPAND_SZ) {
266 /* Advise ExpandEnvironmentStrings that we have a zero char
267 * buffer to force computation of the required length.
268 */
269 char zbuf[1];
270 size = ExpandEnvironmentStrings(*result, zbuf, 0);
271 if (size) {
272 char *tmp = *result;
273 *result = apr_palloc(pool, size);
274 size = ExpandEnvironmentStrings(tmp, *result, (DWORD)size);
275 }
276 }
277 }
278 #endif
279 return APR_SUCCESS;
280 }
281
282
ap_regkey_value_set(ap_regkey_t * key,const char * valuename,const char * value,apr_int32_t flags,apr_pool_t * pool)283 AP_DECLARE(apr_status_t) ap_regkey_value_set(ap_regkey_t *key,
284 const char *valuename,
285 const char *value,
286 apr_int32_t flags,
287 apr_pool_t *pool)
288 {
289 /* Retrieve a registry string value, and explode any envvars
290 * that the system has configured (e.g. %SystemRoot%/someapp.exe)
291 */
292 LONG rc;
293 apr_size_t size = strlen(value) + 1;
294 DWORD type = (flags & AP_REGKEY_EXPAND) ? REG_EXPAND_SZ : REG_SZ;
295
296 #if APR_HAS_UNICODE_FS
297 IF_WIN_OS_IS_UNICODE
298 {
299 apr_size_t alloclen;
300 apr_size_t valuelen = strlen(valuename) + 1;
301 apr_size_t wvallen = 256;
302 apr_wchar_t wvalname[256];
303 apr_wchar_t *wvalue;
304 apr_status_t rv;
305 rv = apr_conv_utf8_to_ucs2(valuename, &valuelen, wvalname, &wvallen);
306 if (rv != APR_SUCCESS)
307 return rv;
308 else if (valuelen)
309 return APR_ENAMETOOLONG;
310
311 wvallen = alloclen = size;
312 wvalue = apr_palloc(pool, alloclen * 2);
313 rv = apr_conv_utf8_to_ucs2(value, &size, wvalue, &wvallen);
314 if (rv != APR_SUCCESS)
315 return rv;
316 else if (size)
317 return APR_ENAMETOOLONG;
318
319 /* The size is the number of wchars consumed by apr_conv_utf8_to_ucs2
320 * converted to bytes; the trailing L'\0' continues to be counted.
321 */
322 size = (alloclen - wvallen) * 2;
323 rc = RegSetValueExW(key->hkey, wvalname, 0, type,
324 (LPBYTE)wvalue, (DWORD)size);
325 if (rc != ERROR_SUCCESS)
326 return APR_FROM_OS_ERROR(rc);
327 }
328 #endif /* APR_HAS_UNICODE_FS */
329 #if APR_HAS_ANSI_FS
330 ELSE_WIN_OS_IS_ANSI
331 {
332 rc = RegSetValueEx(key->hkey, valuename, 0, type, value, (DWORD)size);
333 if (rc != ERROR_SUCCESS)
334 return APR_FROM_OS_ERROR(rc);
335 }
336 #endif
337 return APR_SUCCESS;
338 }
339
340
ap_regkey_value_raw_get(void ** result,apr_size_t * resultsize,apr_int32_t * resulttype,ap_regkey_t * key,const char * valuename,apr_pool_t * pool)341 AP_DECLARE(apr_status_t) ap_regkey_value_raw_get(void **result,
342 apr_size_t *resultsize,
343 apr_int32_t *resulttype,
344 ap_regkey_t *key,
345 const char *valuename,
346 apr_pool_t *pool)
347 {
348 /* Retrieve a registry string value, and explode any envvars
349 * that the system has configured (e.g. %SystemRoot%/someapp.exe)
350 */
351 LONG rc;
352
353 #if APR_HAS_UNICODE_FS
354 IF_WIN_OS_IS_UNICODE
355 {
356 apr_size_t valuelen = strlen(valuename) + 1;
357 apr_size_t wvallen = 256;
358 apr_wchar_t wvalname[256];
359 apr_status_t rv;
360 rv = apr_conv_utf8_to_ucs2(valuename, &valuelen, wvalname, &wvallen);
361 if (rv != APR_SUCCESS)
362 return rv;
363 else if (valuelen)
364 return APR_ENAMETOOLONG;
365 /* Read to NULL buffer to determine value size */
366 rc = RegQueryValueExW(key->hkey, wvalname, 0, (LPDWORD)resulttype,
367 NULL, (LPDWORD)resultsize);
368 if (rc != ERROR_SUCCESS) {
369 return APR_FROM_OS_ERROR(rc);
370 }
371
372 /* Read value based on size query above */
373 *result = apr_palloc(pool, *resultsize);
374 rc = RegQueryValueExW(key->hkey, wvalname, 0, (LPDWORD)resulttype,
375 (LPBYTE)*result, (LPDWORD)resultsize);
376 }
377 #endif /* APR_HAS_UNICODE_FS */
378 #if APR_HAS_ANSI_FS
379 ELSE_WIN_OS_IS_ANSI
380 {
381 /* Read to NULL buffer to determine value size */
382 rc = RegQueryValueEx(key->hkey, valuename, 0, (LPDWORD)resulttype,
383 NULL, (LPDWORD)resultsize);
384 if (rc != ERROR_SUCCESS)
385 return APR_FROM_OS_ERROR(rc);
386
387 /* Read value based on size query above */
388 *result = apr_palloc(pool, *resultsize);
389 rc = RegQueryValueEx(key->hkey, valuename, 0, (LPDWORD)resulttype,
390 (LPBYTE)*result, (LPDWORD)resultsize);
391 if (rc != ERROR_SUCCESS)
392 return APR_FROM_OS_ERROR(rc);
393 }
394 #endif
395 if (rc != ERROR_SUCCESS) {
396 return APR_FROM_OS_ERROR(rc);
397 }
398
399 return APR_SUCCESS;
400 }
401
402
ap_regkey_value_raw_set(ap_regkey_t * key,const char * valuename,const void * value,apr_size_t valuesize,apr_int32_t valuetype,apr_pool_t * pool)403 AP_DECLARE(apr_status_t) ap_regkey_value_raw_set(ap_regkey_t *key,
404 const char *valuename,
405 const void *value,
406 apr_size_t valuesize,
407 apr_int32_t valuetype,
408 apr_pool_t *pool)
409 {
410 LONG rc;
411
412 #if APR_HAS_UNICODE_FS
413 IF_WIN_OS_IS_UNICODE
414 {
415 apr_size_t valuelen = strlen(valuename) + 1;
416 apr_size_t wvallen = 256;
417 apr_wchar_t wvalname[256];
418 apr_status_t rv;
419 rv = apr_conv_utf8_to_ucs2(valuename, &valuelen, wvalname, &wvallen);
420 if (rv != APR_SUCCESS)
421 return rv;
422 else if (valuelen)
423 return APR_ENAMETOOLONG;
424
425 rc = RegSetValueExW(key->hkey, wvalname, 0, valuetype,
426 (LPBYTE)value, (DWORD)valuesize);
427 }
428 #endif /* APR_HAS_UNICODE_FS */
429 #if APR_HAS_ANSI_FS
430 ELSE_WIN_OS_IS_ANSI
431 {
432 rc = RegSetValueEx(key->hkey, valuename, 0, valuetype,
433 (LPBYTE)value, (DWORD)valuesize);
434 }
435 #endif
436 if (rc != ERROR_SUCCESS) {
437 return APR_FROM_OS_ERROR(rc);
438 }
439 return APR_SUCCESS;
440 }
441
442
ap_regkey_value_array_get(apr_array_header_t ** result,ap_regkey_t * key,const char * valuename,apr_pool_t * pool)443 AP_DECLARE(apr_status_t) ap_regkey_value_array_get(apr_array_header_t **result,
444 ap_regkey_t *key,
445 const char *valuename,
446 apr_pool_t *pool)
447 {
448 /* Retrieve a registry string value, and explode any envvars
449 * that the system has configured (e.g. %SystemRoot%/someapp.exe)
450 */
451 apr_status_t rv;
452 void *value;
453 char *buf;
454 char *tmp;
455 apr_int32_t type;
456 apr_size_t size = 0;
457
458 rv = ap_regkey_value_raw_get(&value, &size, &type, key, valuename, pool);
459 if (rv != APR_SUCCESS) {
460 return rv;
461 }
462 else if (type != REG_MULTI_SZ) {
463 return APR_EINVAL;
464 }
465
466 #if APR_HAS_UNICODE_FS
467 IF_WIN_OS_IS_UNICODE
468 {
469 apr_size_t alloclen;
470 apr_size_t valuelen = strlen(valuename) + 1;
471
472 /* ###: deliberately overallocate plus two extra nulls.
473 * We could precalculate the exact buffer here instead, the question
474 * is a matter of storage v.s. cpu cycles.
475 */
476 size /= 2;
477 alloclen = valuelen = size * 3 + 2;
478 buf = apr_palloc(pool, valuelen);
479 rv = apr_conv_ucs2_to_utf8(value, &size, buf, &valuelen);
480 if (rv != APR_SUCCESS)
481 return rv;
482 else if (size)
483 return APR_ENAMETOOLONG;
484 buf[(alloclen - valuelen)] = '\0';
485 buf[(alloclen - valuelen) + 1] = '\0';
486 }
487 #endif /* APR_HAS_UNICODE_FS */
488 #if APR_HAS_ANSI_FS
489 ELSE_WIN_OS_IS_ANSI
490 {
491 /* Small possiblity the array is either unterminated
492 * or single NULL terminated. Avert.
493 */
494 buf = (char *)value;
495 if (size < 2 || buf[size - 1] != '\0' || buf[size - 2] != '\0') {
496 buf = apr_palloc(pool, size + 2);
497 memcpy(buf, value, size);
498 buf[size + 1] = '\0';
499 buf[size] = '\0';
500 }
501 }
502 #endif
503
504 size = 0; /* Element Count */
505 for (tmp = buf; *tmp; ++tmp) {
506 ++size;
507 while (*tmp) {
508 ++tmp;
509 }
510 }
511
512 *result = apr_array_make(pool, (int)size, sizeof(char *));
513 for (tmp = buf; *tmp; ++tmp) {
514 char **newelem = (char **) apr_array_push(*result);
515 *newelem = tmp;
516 while (*tmp) {
517 ++tmp;
518 }
519 }
520
521 return APR_SUCCESS;
522 }
523
524
ap_regkey_value_array_set(ap_regkey_t * key,const char * valuename,int nelts,const char * const * elts,apr_pool_t * pool)525 AP_DECLARE(apr_status_t) ap_regkey_value_array_set(ap_regkey_t *key,
526 const char *valuename,
527 int nelts,
528 const char * const * elts,
529 apr_pool_t *pool)
530 {
531 /* Retrieve a registry string value, and explode any envvars
532 * that the system has configured (e.g. %SystemRoot%/someapp.exe)
533 */
534 int i;
535 const void *value;
536 apr_size_t bufsize;
537
538 #if APR_HAS_UNICODE_FS
539 IF_WIN_OS_IS_UNICODE
540 {
541 apr_status_t rv;
542 apr_wchar_t *buf;
543 apr_wchar_t *tmp;
544 apr_size_t bufrem;
545
546 bufsize = 1; /* For trailing second null */
547 for (i = 0; i < nelts; ++i) {
548 bufsize += strlen(elts[i]) + 1;
549 }
550 if (!nelts) {
551 ++bufsize;
552 }
553
554 bufrem = bufsize;
555 buf = apr_palloc(pool, bufsize * 2);
556 tmp = buf;
557 for (i = 0; i < nelts; ++i) {
558 apr_size_t eltsize = strlen(elts[i]) + 1;
559 apr_size_t size = eltsize;
560 rv = apr_conv_utf8_to_ucs2(elts[i], &size, tmp, &bufrem);
561 if (rv != APR_SUCCESS)
562 return rv;
563 else if (size)
564 return APR_ENAMETOOLONG;
565 tmp += eltsize;
566 }
567 if (!nelts) {
568 --bufrem;
569 (*tmp++) = L'\0';
570 }
571 --bufrem;
572 *tmp = L'\0'; /* Trailing second null */
573
574 bufsize = (bufsize - bufrem) * 2;
575 value = (void*)buf;
576 }
577 #endif /* APR_HAS_UNICODE_FS */
578 #if APR_HAS_ANSI_FS
579 ELSE_WIN_OS_IS_ANSI
580 {
581 char *buf;
582 char *tmp;
583
584 bufsize = 1; /* For trailing second null */
585 for (i = 0; i < nelts; ++i) {
586 bufsize += strlen(elts[i]) + 1;
587 }
588 if (!nelts) {
589 ++bufsize;
590 }
591 buf = apr_palloc(pool, bufsize);
592 tmp = buf;
593 for (i = 0; i < nelts; ++i) {
594 apr_size_t len = strlen(elts[i]) + 1;
595 memcpy(tmp, elts[i], len);
596 tmp += len;
597 }
598 if (!nelts) {
599 (*tmp++) = '\0';
600 }
601 *tmp = '\0'; /* Trailing second null */
602 value = buf;
603 }
604 #endif
605 return ap_regkey_value_raw_set(key, valuename, value,
606 bufsize, REG_MULTI_SZ, pool);
607 }
608
609
ap_regkey_value_remove(const ap_regkey_t * key,const char * valuename,apr_pool_t * pool)610 AP_DECLARE(apr_status_t) ap_regkey_value_remove(const ap_regkey_t *key,
611 const char *valuename,
612 apr_pool_t *pool)
613 {
614 LONG rc;
615
616 #if APR_HAS_UNICODE_FS
617 IF_WIN_OS_IS_UNICODE
618 {
619 apr_size_t valuelen = strlen(valuename) + 1;
620 apr_size_t wvallen = 256;
621 apr_wchar_t wvalname[256];
622 apr_status_t rv = apr_conv_utf8_to_ucs2(valuename, &valuelen, wvalname, &wvallen);
623 if (rv != APR_SUCCESS)
624 return rv;
625 else if (valuelen)
626 return APR_ENAMETOOLONG;
627 rc = RegDeleteValueW(key->hkey, wvalname);
628 }
629 #endif /* APR_HAS_UNICODE_FS */
630 #if APR_HAS_ANSI_FS
631 ELSE_WIN_OS_IS_ANSI
632 {
633 rc = RegDeleteValue(key->hkey, valuename);
634 }
635 #endif
636 if (rc != ERROR_SUCCESS) {
637 return APR_FROM_OS_ERROR(rc);
638 }
639 return APR_SUCCESS;
640 }
641
642 #endif /* defined WIN32 */
643