Main Page | Modules | Namespace List | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals | Related Pages | Examples

ap_regkey.c

Go to the documentation of this file.
00001 /* Copyright 2002-2005 The Apache Software Foundation or its licensors, as
00002  * applicable.
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 #ifdef WIN32
00018 
00019 #include "apr.h"
00020 #include "arch/win32/apr_arch_file_io.h"
00021 #include "arch/win32/apr_arch_misc.h"
00022 #include "ap_regkey.h"
00023 
00024 struct ap_regkey_t {
00025     apr_pool_t *pool;
00026     HKEY        hkey;
00027 };
00028 
00029 
00030 AP_DECLARE(const ap_regkey_t *) ap_regkey_const(int i)
00031 {
00032     static struct ap_regkey_t ap_regkey_consts[7] = 
00033     {
00034         {NULL, HKEY_CLASSES_ROOT},
00035         {NULL, HKEY_CURRENT_CONFIG},
00036         {NULL, HKEY_CURRENT_USER},
00037         {NULL, HKEY_LOCAL_MACHINE},
00038         {NULL, HKEY_USERS},
00039         {NULL, HKEY_PERFORMANCE_DATA},
00040         {NULL, HKEY_DYN_DATA}
00041     };
00042     return ap_regkey_consts + i;
00043 }
00044 
00045 
00046 apr_status_t regkey_cleanup(void *key)
00047 {
00048     ap_regkey_t *regkey = key;
00049 
00050     if (regkey->hkey && regkey->hkey != INVALID_HANDLE_VALUE) {
00051         RegCloseKey(regkey->hkey);
00052         regkey->hkey = INVALID_HANDLE_VALUE;
00053     }
00054     return APR_SUCCESS;
00055 }
00056 
00057 
00058 AP_DECLARE(apr_status_t) ap_regkey_open(ap_regkey_t **newkey, 
00059                                         const ap_regkey_t *parentkey,
00060                                         const char *keyname,
00061                                         apr_int32_t flags, 
00062                                         apr_pool_t *pool)
00063 {
00064     DWORD access = KEY_QUERY_VALUE;
00065     DWORD exists;
00066     HKEY hkey;
00067     LONG rc;
00068 
00069     if (flags & APR_READ)
00070         access |= KEY_READ;
00071     if (flags & APR_WRITE)
00072         access |= KEY_WRITE; 
00073 
00074 #if APR_HAS_UNICODE_FS
00075     IF_WIN_OS_IS_UNICODE 
00076     {
00077         apr_size_t keylen = strlen(keyname) + 1;
00078         apr_size_t wkeylen = 256;
00079         apr_wchar_t wkeyname[256];
00080         apr_status_t rv = apr_conv_utf8_to_ucs2(keyname, &keylen, wkeyname, &wkeylen);
00081         if (rv != APR_SUCCESS)
00082             return rv;
00083         else if (keylen)
00084             return APR_ENAMETOOLONG;
00085 
00086         if (flags & APR_CREATE)
00087             rc = RegCreateKeyExW(parentkey->hkey, wkeyname, 0, NULL, 0, 
00088                                  access, NULL, &hkey, &exists);
00089         else
00090             rc = RegOpenKeyExW(parentkey->hkey, wkeyname, 0, access, &hkey);
00091     }
00092 #endif /* APR_HAS_UNICODE_FS */
00093 #if APR_HAS_ANSI_FS
00094     ELSE_WIN_OS_IS_ANSI
00095     {
00096         if (flags & APR_CREATE)
00097             rc = RegCreateKeyEx(parentkey->hkey, keyname, 0, NULL, 0, 
00098                                 access, NULL, &hkey, &exists);
00099         else
00100             rc = RegOpenKeyEx(parentkey->hkey, keyname, 0, access, &hkey);
00101     }
00102 #endif
00103     if (rc != ERROR_SUCCESS) {
00104         return APR_FROM_OS_ERROR(rc);
00105     }
00106     if ((flags & APR_EXCL) && (exists == REG_OPENED_EXISTING_KEY)) {
00107         RegCloseKey(hkey);
00108         return APR_EEXIST;
00109     }
00110 
00111     *newkey = apr_palloc(pool, sizeof(**newkey));
00112     (*newkey)->pool = pool;
00113     (*newkey)->hkey = hkey;
00114     apr_pool_cleanup_register((*newkey)->pool, (void *)(*newkey), 
00115                               regkey_cleanup, apr_pool_cleanup_null);
00116     return APR_SUCCESS;
00117 }
00118 
00119 
00120 AP_DECLARE(apr_status_t) ap_regkey_close(ap_regkey_t *regkey)
00121 {
00122     apr_status_t stat;
00123     if ((stat = regkey_cleanup(regkey)) == APR_SUCCESS) {
00124         apr_pool_cleanup_kill(regkey->pool, regkey, regkey_cleanup);
00125     }
00126     return stat;
00127 }
00128 
00129 
00130 AP_DECLARE(apr_status_t) ap_regkey_remove(const ap_regkey_t *parent, 
00131                                           const char *keyname,
00132                                           apr_pool_t *pool)
00133 {
00134     LONG rc;
00135 
00136 #if APR_HAS_UNICODE_FS
00137     IF_WIN_OS_IS_UNICODE 
00138     {
00139         apr_size_t keylen = strlen(keyname) + 1;
00140         apr_size_t wkeylen = 256;
00141         apr_wchar_t wkeyname[256];
00142         apr_status_t rv = apr_conv_utf8_to_ucs2(keyname, &keylen, wkeyname, &wkeylen);
00143         if (rv != APR_SUCCESS)
00144             return rv;
00145         else if (keylen)
00146             return APR_ENAMETOOLONG;
00147         rc = RegDeleteKeyW(parent->hkey, wkeyname);
00148     }
00149 #endif /* APR_HAS_UNICODE_FS */
00150 #if APR_HAS_ANSI_FS
00151     ELSE_WIN_OS_IS_ANSI
00152     {
00153         /* We need to determine if subkeys exist on Win9x, to provide
00154          * consistent behavior with NT, which returns access denied
00155          * if subkeys exist when attempting to delete a key.
00156          */
00157         DWORD subkeys;
00158         HKEY hkey;
00159         rc = RegOpenKeyEx(parent->hkey, keyname, 0, KEY_READ, &hkey);
00160         if (rc != ERROR_SUCCESS)
00161             return APR_FROM_OS_ERROR(rc);
00162         rc = RegQueryInfoKey(hkey, NULL, NULL, NULL, &subkeys, NULL, NULL,
00163                              NULL, NULL, NULL, NULL, NULL);
00164         RegCloseKey(hkey);
00165         if (rc != ERROR_SUCCESS)
00166             return APR_FROM_OS_ERROR(rc);
00167         else if (subkeys)
00168             return APR_FROM_OS_ERROR(ERROR_ACCESS_DENIED);
00169         rc = RegDeleteKey(parent->hkey, keyname);
00170     }
00171 #endif
00172     if (rc != ERROR_SUCCESS) {
00173         return APR_FROM_OS_ERROR(rc);
00174     }
00175     return APR_SUCCESS;
00176 }
00177 
00178 
00179 AP_DECLARE(apr_status_t) ap_regkey_value_get(char **result, 
00180                                              ap_regkey_t *key, 
00181                                              const char *valuename, 
00182                                              apr_pool_t *pool)
00183 {
00184     /* Retrieve a registry string value, and explode any envvars
00185      * that the system has configured (e.g. %SystemRoot%/someapp.exe)
00186      */
00187     LONG rc;
00188     DWORD type;
00189     DWORD size = 0;
00190     
00191 #if APR_HAS_UNICODE_FS
00192     IF_WIN_OS_IS_UNICODE 
00193     {
00194         apr_size_t valuelen = strlen(valuename) + 1;
00195         apr_size_t wvallen = 256;
00196         apr_wchar_t wvalname[256];
00197         apr_wchar_t *wvalue;
00198         apr_status_t rv;
00199         rv = apr_conv_utf8_to_ucs2(valuename, &valuelen, wvalname, &wvallen);
00200         if (rv != APR_SUCCESS)
00201             return rv;
00202         else if (valuelen)
00203             return APR_ENAMETOOLONG;
00204         /* Read to NULL buffer to determine value size */
00205         rc = RegQueryValueExW(key->hkey, wvalname, 0, &type, NULL, &size);
00206         if (rc != ERROR_SUCCESS) {
00207             return APR_FROM_OS_ERROR(rc);
00208         }
00209         if ((size < 2) || (type != REG_SZ && type != REG_EXPAND_SZ)) {
00210             return APR_FROM_OS_ERROR(ERROR_INVALID_PARAMETER);
00211         }
00212 
00213         wvalue = apr_palloc(pool, size);
00214         /* Read value based on size query above */
00215         rc = RegQueryValueExW(key->hkey, wvalname, 0, &type, 
00216                               (LPBYTE)wvalue, &size);
00217         if (rc != ERROR_SUCCESS) {
00218             return APR_FROM_OS_ERROR(rc);
00219         }
00220         if (type == REG_EXPAND_SZ) {
00221             apr_wchar_t zbuf[1];
00222             size = ExpandEnvironmentStringsW(wvalue, zbuf, 0);
00223             if (size) {
00224                 apr_wchar_t *tmp = wvalue;
00225                 /* The size returned by ExpandEnvironmentStringsW is wchars */
00226                 wvalue = apr_palloc(pool, size * 2);
00227                 size = ExpandEnvironmentStringsW(tmp, wvalue, size);
00228             }
00229         }
00230         else {
00231             /* count wchars from RegQueryValueExW, rather than bytes */
00232             size /= 2;
00233         }
00234         /* ###: deliberately overallocate all but the trailing null.
00235          * We could precalculate the exact buffer here instead, the question
00236          * is a matter of storage v.s. cpu cycles.
00237          */
00238         valuelen = (size - 1) * 3 + 1;
00239         *result = apr_palloc(pool, valuelen);
00240         rv = apr_conv_ucs2_to_utf8(wvalue, &size, *result, &valuelen);
00241         if (rv != APR_SUCCESS)
00242             return rv;
00243         else if (size)
00244             return APR_ENAMETOOLONG;
00245     }
00246 #endif /* APR_HAS_UNICODE_FS */
00247 #if APR_HAS_ANSI_FS
00248     ELSE_WIN_OS_IS_ANSI
00249     {
00250         /* Read to NULL buffer to determine value size */
00251         rc = RegQueryValueEx(key->hkey, valuename, 0, &type, NULL, &size);
00252         if (rc != ERROR_SUCCESS)
00253             return APR_FROM_OS_ERROR(rc);
00254 
00255         if ((size < 1) || (type != REG_SZ && type != REG_EXPAND_SZ)) {
00256             return APR_FROM_OS_ERROR(ERROR_INVALID_PARAMETER);
00257         }
00258 
00259         *result = apr_palloc(pool, size);
00260         /* Read value based on size query above */
00261         rc = RegQueryValueEx(key->hkey, valuename, 0, &type, *result, &size);
00262         if (rc != ERROR_SUCCESS)
00263             return APR_FROM_OS_ERROR(rc);
00264 
00265         if (type == REG_EXPAND_SZ) {
00266             /* Advise ExpandEnvironmentStrings that we have a zero char
00267              * buffer to force computation of the required length.
00268              */
00269             char zbuf[1];
00270             size = ExpandEnvironmentStrings(*result, zbuf, 0);
00271             if (size) {
00272                 char *tmp = *result;
00273                 *result = apr_palloc(pool, size);
00274                 size = ExpandEnvironmentStrings(tmp, *result, size);
00275             }
00276         }
00277     }
00278 #endif
00279     return APR_SUCCESS;
00280 }
00281 
00282 
00283 AP_DECLARE(apr_status_t) ap_regkey_value_set(ap_regkey_t *key, 
00284                                              const char *valuename, 
00285                                              const char *value, 
00286                                              apr_int32_t flags, 
00287                                              apr_pool_t *pool)
00288 {
00289     /* Retrieve a registry string value, and explode any envvars
00290      * that the system has configured (e.g. %SystemRoot%/someapp.exe)
00291      */
00292     LONG rc;
00293     DWORD size = strlen(value) + 1;
00294     DWORD type = (flags & AP_REGKEY_EXPAND) ? REG_EXPAND_SZ : REG_SZ;
00295     
00296 #if APR_HAS_UNICODE_FS
00297     IF_WIN_OS_IS_UNICODE 
00298     {
00299         apr_size_t alloclen;
00300         apr_size_t valuelen = strlen(valuename) + 1;
00301         apr_size_t wvallen = 256;
00302         apr_wchar_t wvalname[256];
00303         apr_wchar_t *wvalue;
00304         apr_status_t rv;
00305         rv = apr_conv_utf8_to_ucs2(valuename, &valuelen, wvalname, &wvallen);
00306         if (rv != APR_SUCCESS)
00307             return rv;
00308         else if (valuelen)
00309             return APR_ENAMETOOLONG;
00310         
00311         wvallen = alloclen = size;
00312         wvalue = apr_palloc(pool, alloclen * 2);
00313         rv = apr_conv_utf8_to_ucs2(value, &size, wvalue, &wvallen);
00314         if (rv != APR_SUCCESS)
00315             return rv;
00316         else if (size)
00317             return APR_ENAMETOOLONG;
00318 
00319         /* The size is the number of wchars consumed by apr_conv_utf8_to_ucs2
00320          * converted to bytes; the trailing L'\0' continues to be counted.
00321          */
00322         size = (alloclen - wvallen) * 2;
00323         rc = RegSetValueExW(key->hkey, wvalname, 0, type, 
00324                             (LPBYTE)wvalue, size);
00325         if (rc != ERROR_SUCCESS)
00326             return APR_FROM_OS_ERROR(rc);
00327     }
00328 #endif /* APR_HAS_UNICODE_FS */
00329 #if APR_HAS_ANSI_FS
00330     ELSE_WIN_OS_IS_ANSI
00331     {
00332         rc = RegSetValueEx(key->hkey, valuename, 0, type, value, size);
00333         if (rc != ERROR_SUCCESS)
00334             return APR_FROM_OS_ERROR(rc);
00335     }
00336 #endif
00337     return APR_SUCCESS;
00338 }
00339 
00340 
00341 AP_DECLARE(apr_status_t) ap_regkey_value_raw_get(void **result, 
00342                                                  apr_size_t *resultsize,
00343                                                  apr_int32_t *resulttype,
00344                                                  ap_regkey_t *key, 
00345                                                  const char *valuename, 
00346                                                  apr_pool_t *pool)
00347 {
00348     /* Retrieve a registry string value, and explode any envvars
00349      * that the system has configured (e.g. %SystemRoot%/someapp.exe)
00350      */
00351     LONG rc;
00352     
00353 #if APR_HAS_UNICODE_FS
00354     IF_WIN_OS_IS_UNICODE 
00355     {
00356         apr_size_t valuelen = strlen(valuename) + 1;
00357         apr_size_t wvallen = 256;
00358         apr_wchar_t wvalname[256];
00359         apr_status_t rv;
00360         rv = apr_conv_utf8_to_ucs2(valuename, &valuelen, wvalname, &wvallen);
00361         if (rv != APR_SUCCESS)
00362             return rv;
00363         else if (valuelen)
00364             return APR_ENAMETOOLONG;
00365         /* Read to NULL buffer to determine value size */
00366         rc = RegQueryValueExW(key->hkey, wvalname, 0, resulttype, 
00367                               NULL, resultsize);
00368         if (rc != ERROR_SUCCESS) {
00369             return APR_FROM_OS_ERROR(rc);
00370         }
00371 
00372         /* Read value based on size query above */
00373         *result = apr_palloc(pool, *resultsize);
00374         rc = RegQueryValueExW(key->hkey, wvalname, 0, resulttype, 
00375                              (LPBYTE)*result, resultsize);
00376     }
00377 #endif /* APR_HAS_UNICODE_FS */
00378 #if APR_HAS_ANSI_FS
00379     ELSE_WIN_OS_IS_ANSI
00380     {
00381         /* Read to NULL buffer to determine value size */
00382         rc = RegQueryValueEx(key->hkey, valuename, 0, resulttype, 
00383                              NULL, resultsize);
00384         if (rc != ERROR_SUCCESS)
00385             return APR_FROM_OS_ERROR(rc);
00386 
00387         /* Read value based on size query above */
00388         *result = apr_palloc(pool, *resultsize);
00389         rc = RegQueryValueEx(key->hkey, valuename, 0, resulttype, 
00390                              (LPBYTE)*result, resultsize);
00391         if (rc != ERROR_SUCCESS)
00392             return APR_FROM_OS_ERROR(rc);
00393     }
00394 #endif
00395     if (rc != ERROR_SUCCESS) {
00396         return APR_FROM_OS_ERROR(rc);
00397     }
00398 
00399     return APR_SUCCESS;
00400 }
00401 
00402 
00403 AP_DECLARE(apr_status_t) ap_regkey_value_raw_set(ap_regkey_t *key, 
00404                                                  const char *valuename, 
00405                                                  const void *value, 
00406                                                  apr_size_t valuesize,
00407                                                  apr_int32_t valuetype,
00408                                                  apr_pool_t *pool)
00409 {
00410     LONG rc;
00411     
00412 #if APR_HAS_UNICODE_FS
00413     IF_WIN_OS_IS_UNICODE 
00414     {
00415         apr_size_t valuelen = strlen(valuename) + 1;
00416         apr_size_t wvallen = 256;
00417         apr_wchar_t wvalname[256];
00418         apr_status_t rv;
00419         rv = apr_conv_utf8_to_ucs2(valuename, &valuelen, wvalname, &wvallen);
00420         if (rv != APR_SUCCESS)
00421             return rv;
00422         else if (valuelen)
00423             return APR_ENAMETOOLONG;
00424 
00425         rc = RegSetValueExW(key->hkey, wvalname, 0, valuetype, 
00426                             (LPBYTE)value, valuesize);
00427     }
00428 #endif /* APR_HAS_UNICODE_FS */
00429 #if APR_HAS_ANSI_FS
00430     ELSE_WIN_OS_IS_ANSI
00431     {
00432         rc = RegSetValueEx(key->hkey, valuename, 0, valuetype, 
00433                             (LPBYTE)value, valuesize);
00434     }
00435 #endif
00436     if (rc != ERROR_SUCCESS) {
00437         return APR_FROM_OS_ERROR(rc);
00438     }
00439     return APR_SUCCESS;
00440 }
00441 
00442 
00443 AP_DECLARE(apr_status_t) ap_regkey_value_array_get(apr_array_header_t **result, 
00444                                                    ap_regkey_t *key,
00445                                                    const char *valuename, 
00446                                                    apr_pool_t *pool)
00447 {
00448     /* Retrieve a registry string value, and explode any envvars
00449      * that the system has configured (e.g. %SystemRoot%/someapp.exe)
00450      */
00451     apr_status_t rv;
00452     void *value;
00453     char *buf;
00454     char *tmp;
00455     DWORD type;
00456     DWORD size = 0;
00457 
00458     rv = ap_regkey_value_raw_get(&value, &size, &type, key, valuename, pool);
00459     if (rv != APR_SUCCESS) {
00460         return rv;
00461     }
00462     else if (type != REG_MULTI_SZ) {
00463         return APR_EINVAL;
00464     }
00465 
00466 #if APR_HAS_UNICODE_FS
00467     IF_WIN_OS_IS_UNICODE 
00468     {
00469         apr_size_t alloclen;
00470         apr_size_t valuelen = strlen(valuename) + 1;
00471         apr_size_t wvallen = 256;
00472         apr_wchar_t *wvalue = (apr_wchar_t *)value;
00473 
00474         /* ###: deliberately overallocate plus two extra nulls.
00475          * We could precalculate the exact buffer here instead, the question
00476          * is a matter of storage v.s. cpu cycles.
00477          */
00478         size /= 2;
00479         alloclen = valuelen = size * 3 + 2;
00480         buf = apr_palloc(pool, valuelen);
00481         rv = apr_conv_ucs2_to_utf8(value, &size, buf, &valuelen);
00482         if (rv != APR_SUCCESS)
00483             return rv;
00484         else if (size)
00485             return APR_ENAMETOOLONG;
00486         buf[(alloclen - valuelen)] = '\0';
00487         buf[(alloclen - valuelen) + 1] = '\0';
00488     }
00489 #endif /* APR_HAS_UNICODE_FS */
00490 #if APR_HAS_ANSI_FS
00491     ELSE_WIN_OS_IS_ANSI
00492     {
00493         /* Small possiblity the array is either unterminated 
00494          * or single NULL terminated.  Avert.
00495          */
00496         buf = (char *)value;
00497         if (size < 2 || buf[size - 1] != '\0' || buf[size - 2] != '\0') {
00498             buf = apr_palloc(pool, size + 2);
00499             memcpy(buf, value, size);
00500             buf[size + 1] = '\0';
00501             buf[size] = '\0';
00502         }
00503     }
00504 #endif
00505 
00506     size = 0;    /* Element Count */
00507     for (tmp = buf; *tmp; ++tmp) {
00508         ++size;
00509         while (*tmp) {
00510             ++tmp;
00511         }
00512     }
00513 
00514     *result = apr_array_make(pool, size, sizeof(char *));
00515     for (tmp = buf; *tmp; ++tmp) {
00516         char **newelem = (char **) apr_array_push(*result);
00517         *newelem = tmp;
00518         while (*tmp) {
00519             ++tmp;
00520         }
00521     }
00522 
00523    return APR_SUCCESS;
00524 }
00525 
00526 
00527 AP_DECLARE(apr_status_t) ap_regkey_value_array_set(ap_regkey_t *key, 
00528                                                    const char *valuename, 
00529                                                    int nelts, 
00530                                                    const char * const * elts,
00531                                                    apr_pool_t *pool)
00532 {
00533     /* Retrieve a registry string value, and explode any envvars
00534      * that the system has configured (e.g. %SystemRoot%/someapp.exe)
00535      */
00536     int i;
00537     const void *value;
00538     apr_size_t bufsize;
00539     
00540 #if APR_HAS_UNICODE_FS
00541     IF_WIN_OS_IS_UNICODE 
00542     {
00543         apr_status_t rv;
00544         apr_wchar_t *buf;
00545         apr_wchar_t *tmp;
00546         apr_size_t bufrem;
00547 
00548         bufsize = 1; /* For trailing second null */
00549         for (i = 0; i < nelts; ++i) {
00550             bufsize += strlen(elts[i]) + 1;
00551         }
00552         if (!nelts) {
00553             ++bufsize;
00554         }
00555 
00556         bufrem = bufsize;
00557         buf = apr_palloc(pool, bufsize * 2);
00558         tmp = buf;
00559         for (i = 0; i < nelts; ++i) {
00560             apr_size_t eltsize = strlen(elts[i]) + 1;
00561             apr_size_t size = eltsize;
00562             rv = apr_conv_utf8_to_ucs2(elts[i], &size, tmp, &bufrem);
00563             if (rv != APR_SUCCESS)
00564                 return rv;
00565             else if (size)
00566                 return APR_ENAMETOOLONG;
00567             tmp += eltsize;
00568         }
00569         if (!nelts) {
00570             --bufrem;
00571             (*tmp++) = L'\0';
00572         }
00573         --bufrem;
00574         *tmp = L'\0'; /* Trailing second null */
00575 
00576         bufsize = (bufsize - bufrem) * 2;
00577         value = (void*)buf;
00578     }
00579 #endif /* APR_HAS_UNICODE_FS */
00580 #if APR_HAS_ANSI_FS
00581     ELSE_WIN_OS_IS_ANSI
00582     {
00583         char *buf;
00584         char *tmp;
00585 
00586         bufsize = 1; /* For trailing second null */
00587         for (i = 0; i < nelts; ++i) {
00588             bufsize += strlen(elts[i]) + 1;
00589         }
00590         if (!nelts) {
00591             ++bufsize;
00592         }
00593         buf = apr_palloc(pool, bufsize);
00594         tmp = buf;
00595         for (i = 0; i < nelts; ++i) {
00596             apr_size_t len = strlen(elts[i]) + 1;
00597             memcpy(tmp, elts[i], len);
00598             tmp += len;
00599         }
00600         if (!nelts) {
00601             (*tmp++) = '\0';
00602         }
00603         *tmp = '\0'; /* Trailing second null */
00604         value = buf;
00605     }
00606 #endif
00607     return ap_regkey_value_raw_set(key, valuename, value, 
00608                                    bufsize, REG_MULTI_SZ, pool);
00609 }
00610 
00611 
00612 AP_DECLARE(apr_status_t) ap_regkey_value_remove(const ap_regkey_t *key, 
00613                                                 const char *valuename,
00614                                                 apr_pool_t *pool)
00615 {
00616     LONG rc;
00617 
00618 #if APR_HAS_UNICODE_FS
00619     IF_WIN_OS_IS_UNICODE 
00620     {
00621         apr_size_t valuelen = strlen(valuename) + 1;
00622         apr_size_t wvallen = 256;
00623         apr_wchar_t wvalname[256];
00624         apr_status_t rv = apr_conv_utf8_to_ucs2(valuename, &valuelen, wvalname, &wvallen);
00625         if (rv != APR_SUCCESS)
00626             return rv;
00627         else if (valuelen)
00628             return APR_ENAMETOOLONG;
00629         rc = RegDeleteValueW(key->hkey, wvalname);
00630     }
00631 #endif /* APR_HAS_UNICODE_FS */
00632 #if APR_HAS_ANSI_FS
00633     ELSE_WIN_OS_IS_ANSI
00634     {
00635         rc = RegDeleteValue(key->hkey, valuename);
00636     }
00637 #endif
00638     if (rc != ERROR_SUCCESS) {
00639         return APR_FROM_OS_ERROR(rc);
00640     }
00641     return APR_SUCCESS;
00642 }
00643 
00644 #endif /* defined WIN32 */