2013-03-21 10 views
4

Привет, я использую delphi FM2 с XE3 в окнах 8.Как получить имя текущего пользователя в delphi?

Проблема, связанная с тем, что я хочу, чтобы пользователь нажал кнопку, а затем перейдите к подпапке, расположенной в appdata ex. C: \ Users \ Kobus \ AppData \ Roaming.minecraft

У каждого есть другое имя пользователя, поэтому это не будет работать.

Так я использую этот код, чтобы получить имя пользователя:

function GetCurrentUserName : string; 
const 
    cnMaxUserNameLen = 254; 
var 
    sUserName  : string; 
    dwUserNameLen : DWord; 
begin 
    dwUserNameLen := cnMaxUserNameLen-1; 
    SetLength(sUserName, cnMaxUserNameLen); 
    GetUserName(PChar(sUserName),dwUserNameLen); 
    SetLength(sUserName, dwUserNameLen); 
    Result := sUserName; 
end; 

username := GetCurrentUserName; 

Тогда я говорю ShowMessage('C:\Users\'+username+'\AppData\Roaming\.minecraft\saves\'); проверить вывод.

И вывод, который я получаю, это: «C: \ Users \ Kobus» по какой-то причине остальная часть имени пути теряется.

Что мне нужно быть отображаемым: 'C: \ Users \' Кобус '\ AppData \ Roaming.minecraft \ сохраняет \'

Спасибо.

+4

В системе под управлением Windows XP вы имеете в виду 'C: \ Documents and Settings \ <Политика конфиденциальности>' и т. Д. Возможно. Вы не знаете, что такое путь, даже если вы знаете имя пользователя. Используйте функцию ['SHGetSpecialFolderPath'] (http://msdn.microsoft.com/en-us/library/windows/desktop/bb762204 (v = vs.85) .aspx). –

ответ

12

Проблема заключается в том, что dwUserNameLen содержит длину строки, включая конечный нулевой терминатор. Так что, когда вы делаете:

SetLength(sUserName, dwUserNameLen); 

это приводит к sUserName быть установлен в 'Kobus#0'. В какой-то момент вы передаете это в диалоговую функцию Windows API, которая обрабатывает строку как строку с завершающим нулем и обрезает строку на блуждающем нуль-терминаторе.

Так вы исправить это следующим образом:

SetLength(sUserName, dwUserNameLen-1); 

Обратите внимание, что вы должны также проверить возвращаемое значение GetUserName в случае, если вызов не выполняется:

if not GetUserName(PChar(sUserName), dwUserNameLen) then 
    RaiseLastOSError; 

или довольно отчетливый вариант:

Win32Check(GetUserName(PChar(sUserName), dwUserNameLen)); 

Конечный пункт. Это неправильный способ получить папку данных о роуминге. Для начала вы принимаете всевозможные детали реализации. Ваш подход не будет работать в старых версиях Windows, которые используют разные шаблоны имен. Или в будущей версии Windows. Или текущие версии, которые были настроены по-другому.

Правильный способ сделать это - спросить систему, в которой находится папка данных роуминг-приложения. Сделайте это с помощью CSIDL_APPDATA (для более старых версий Windows) или FOLDERID_RoamingAppData (для современных версий Windows).

+3

+1 для части «Одна конечная точка», которая, безусловно, является самой важной частью ответа. –

+0

Спасибо за помощь, которую вы пытаетесь сделать, как вы сказали в последнем пункте. –

+0

Лично я бы сделал 'SetLength (sUserName, StrLen (sUserName)),' здесь. Или даже ленивое 'sUserName: = PChar (sUserName);'. Поскольку этот вызов Win32 APi не возвращает несколько строк, разделенных несколькими нулями, 'dwUserNameLen' можно просто игнорировать. –

-2
username := GetEnvironmentVariable('username'); 

наборы username на имя текущего пользователя, избавляя сложность.

+0

Ответ, который содержит только код, как правило, является плохим ответом. Вы должны попытаться объяснить, что делает код, и как он решает проблему, и отвечает на заданный вопрос. –

+0

Самая большая проблема с этим ответом ИМХО заключается в том, что он не может обратиться к основной проблеме в подходе OP. –

+0

Ну, если хотите. Я бы предположил, что это было достаточно очевидно. Ответ на заданный вопрос: «Как получить имя текущего пользователя в delphi». Простейший метод ИМО. – Magoo

1

Мне не нужно было рыть слишком долго, чтобы найти фрагмент :). Так что я использую в моем приложении, после подведения итогов намеков, становится:

//================================================================= 
procedure TMainF1.UserTestClick(Sender: TObject); 
const 
    cnMaxUserNameLen = 254; 
var 
    sUserName  : string; 
    dwUserNameLen : DWord; 
begin 
    dwUserNameLen := cnMaxUserNameLen-1; 
    SetLength(sUserName, cnMaxUserNameLen); 
    Win32Check(GetUserName(PChar(sUserName), dwUserNameLen)); 
    sUserName := PChar(sUserName); 
    label_user.Caption := UpperCase(sUserName); 
end; 

//== works well with D7 
0

Я думаю, что ваш вопрос является одним из XY Problems

Вашей актуальной проблемы, что вы хотите, чтобы прочитать полный путь %AppData%\.minecraft\saves\

и вы думаете, в том, как читать текущий Username

Посмотрите на CSIDL и SHGetFolderPath

function GetShellFolder(CSIDLFolder : integer) : string; 
begin 
    SetLength(Result, MAX_PATH); 
    SHGetSpecialFolderPath(0, PChar(Result), CSIDLFolder, false); 
    SetLength(Result, StrLen(PChar(Result))); 
    if (Result <> '') then 
    Result := IncludeTrailingBackslash(Result); 
end; 

.... 

//Usage 
ShowMessage(GetShellFolder(CSIDL_APPDATA)+'.minecraft\saves'); 

UPDATE

Alternative

Проверить GetHomePath функция System.IOUtils единицы.

Будет делать тот же результат, что и для нескольких платформ.

uses System.IOUtils; 

procedure TForm17.btn1Click(Sender: TObject); 
begin 
    ShowMessage(TPath.GetHomePath() + TPath.DirectorySeparatorChar + '.minecraft\saves'); 
end; 
Смежные вопросы