powered by simpleCommunicator - 2.0.51     © 2025 Programmizd 02
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Разное поведение при копировании ярлыков
3 сообщений из 3, страница 1 из 1
Разное поведение при копировании ярлыков
    #39761773
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Надо программно вытянуть shortcut на рабочий стол.
Ярлык системный (т.е локализован) но на новых OS ярлык как бы есть, но запрятан так глубоко что штатному юзеру с ходу непонятно как добраться.

f - путь к исходному ярлыку (он там "на русском")
Код: c#
1.
IO.File.Copy(f, IO.Path.Combine(pszTargetFolder, IO.Path.GetFileName(f)), True)


Копируется, но становится англиийским.

Попробовал так благо писал сию ф-цию когда-то

Код: vbnet
1.
2.
              'ShellCopyFileFolder(f, IO.Path.Combine(pszTargetFolder, IO.Path.GetFileName(f)))
              ShellCopyFileFolder(f, pszTargetFolder)


Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
  'Shell Structures

  'wFunc - A value that indicates which operation to perform
  Public Const FO_MOVE = &H1
  Public Const FO_COPY = &H2
  Public Const FO_DELETE = &H3
  Public Const FO_RENAME = &H4

  'fFlags - Flags that control the file operation
  'Preserve undo information, if possible (класть в корзину)
  Public Const FOF_ALLOWUNDO = &H40
  'Respond with Yes to All for any dialog box that is displayed
  Public Const FOF_NOCONFIRMATION = &H10
  'Do not ask the user to confirm the creation of a new directory if required
  Public Const FOF_NOCONFIRMMKDIR = &H200
  'Do not copy the security attributes of the file.
  'The destination file receives the security attributes of its new folder.
  Public Const FOF_NOCOPYSECURITYATTRIBS = &H800
  'Do not display a dialog to the user if an error occurs.
  Public Const FOF_NOERRORUI = &H400
  'Do not display a progress dialog box.
  Public Const FOF_SILENT = &H4
  'Display a progress dialog box but do not show individual file names as they are operated on.
  Public Const FOF_SIMPLEPROGRESS = &H100
  'Windows Vista. Perform the operation silently, presenting no UI to the user.
  Public Const FOF_NO_UI = FOF_SILENT Or FOF_NOCONFIRMATION Or FOF_NOCONFIRMMKDIR Or FOF_NOERRORUI

  <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode)>
  Public Structure SHFILEOPSTRUCT
    Dim hwnd As IntPtr
    Dim wFunc As Integer
    Dim pFrom As String
    Dim pTo As String
    Dim fFlags As Short
    Dim fAnyOperationsAborted As Boolean
    Dim hNameMappings As IntPtr
    Dim lpszProgressTitle As String
  End Structure

  Public Declare Unicode Function SHFileOperation Lib "shell32.dll" Alias "SHFileOperationW" _
   (ByRef lpFileOp As SHFILEOPSTRUCT) As Integer

  Public Function ShellCopyFileFolder(ByVal strSource As String, ByVal strTarget As String, _
   Optional ByVal bMove As Boolean = False, _
   Optional ByVal bSilent As Boolean = True, _
   Optional ByVal bNoConfirmMakeDir As Boolean = True, _
   Optional ByVal bNoConfirm As Boolean = True, _
   Optional ByVal bNoShowErrors As Boolean = True, _
   Optional ByVal bNoCopySecurityAttribs As Boolean = True) As Boolean
    'bMove -использовать Move вместо Copy
    'bSilent - не показывать диалог копирования
    'bNoConfirmMakeDir -создавать папку, куда копировать без подтверждения
    'bNoConfirm -не задавать пользователю лишних вопросов
    'bNoShowErrors -не выводить диалоги про ошибки
    'bNoCopySecurityAttribs - не копировать права на исх. файлы и папки

    'ВАЖНО!!! при копировании папок
    'если папка strTarget существует, то папка с именем strSource копируется в strTarget
    'если папка strTarget НЕ существует, то она создается в strTarget и туда копируется содержимое strSource

    Dim SHFileOp As New SHFILEOPSTRUCT  ' structure To pass To the Function
    Dim dwRes As Integer

    'коррекция
    strSource = InCorrectDir(strSource) & Chr(0) & Chr(0) 'убираем "\" на конце и добавляем "\0\0" 
    strTarget = InCorrectDir(strTarget) 'убираем "\" на конце

    With SHFileOp
      If bMove Then
        .wFunc = FO_MOVE
      Else
        .wFunc = FO_COPY
      End If
      .pFrom = strSource
      .pTo = strTarget
      If bSilent Then .fFlags = .fFlags Or FOF_SILENT
      If bNoConfirmMakeDir Then .fFlags = .fFlags Or FOF_NOCONFIRMMKDIR
      If bNoConfirm Then .fFlags = .fFlags Or FOF_NOCONFIRMATION
      If bNoShowErrors Then .fFlags = .fFlags Or FOF_NOERRORUI
      If bNoCopySecurityAttribs Then .fFlags = .fFlags Or FOF_NOCOPYSECURITYATTRIBS
    End With

    dwRes = SHFileOperation(SHFileOp)
    'If dwRes <> 0 Then Debug.Print "SHFileOperation Error " & CStr(dwRes)

    ShellCopyFileFolder = (dwRes = 0)

  End Function

  Public Function InCorrectDir(ByVal the_str As String) As String
    'здесь наоборот удаляем крайний слэш!
    If (Strings.Right(the_str, 1) = "\") Then
      InCorrectDir = Strings.Left(the_str, Strings.Len(the_str) - 1)
    Else
      InCorrectDir = the_str
    End If
  End Function



И все OK - скопированный ярлык тоже с русской локализацией (как и ручками впрочем).
В pszTargetFolder создается desktop.ini, в нем путь к локализованному ресурсу.

Где собака порылась?
...
Рейтинг: 0 / 0
Разное поведение при копировании ярлыков
    #39761895
Фотография Cat2
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
Я верю, что еще при моей жизни в C# появится класс для создания ярлыков!

Ведь в классе управлении службами System.ServiceProcess свойство StartType все же было реализовано в NetFramework 4.6! Не прошло и 20 лет!
До этого надо было читать реестр.
...
Рейтинг: 0 / 0
Разное поведение при копировании ярлыков
    #39761974
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Cat2Я верю, что еще при моей жизни в C# появится класс для создания ярлыков!
Создавать я умею.
Создать / удалить ярлык на рабочем столе программно.
Задача куда более простая.
Готовый ярлык уже есть (мне конкретно нужен ярлык к Fax and Scan).
На Win8.0 и выше он запрятан сюда:
C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Accessories\Windows Fax and Scan.lnk
Даже в замечательном меню Win10, найти папку Стандартные-Windows после всех восьмерок - это не каждый догадается (я только вчера копаючись понял что он там таки штатно есть). На Win7 он еще был на виду по кнопке Start.
Посему возникает естественное желание скопировать оный в
1) SpecialFolder.CommonDesktopDirectory
2) SpecialFolder.CommonPrograms (в корень Start, чтоб был на виду)
Свой делать не хочется, т.к.
1) он локализованный, 2) есть примечание, опять же локализованное 3)придется возиться с перенаправлениями на x64 os в 32-битном коде при вычислении/написании пути для target и т.д.

Ищется так:
Код: vbnet
1.
s_Shortcut_Original = FindShortcutByTagretName(s_CommonPrograms, "WFS.exe", False, False) ' в поддиректориях

Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
  Public Function FindShortcutByTagretName(ByVal pszFolder As String, ByVal pszTargetName As String, _
   Optional bTopDirectoryOnly As Boolean = True, Optional bInTheMiddle As Boolean = False) As String
    'возвращает путь к первому найденному ярлыку, указывающему на имя pszTargetName по заданному пути pszFolder
    'bTopDirectoryOnly - не искать ярлык в поддиректориях
    'bInTheMiddle=false -проверяет точное совпадение pszTargetName с GetFileName(sTarget)
    'bInTheMiddle=true -проверяет вхождение pszTargetName в строку sTarget, напр. pszTargetName='fxsclnt.exe' sTarget='...system32\fxsclnt.exe /new'
    Dim ff As String()
    If bTopDirectoryOnly Then
      ff = IO.Directory.GetFiles(pszFolder, "*.lnk", IO.SearchOption.TopDirectoryOnly)
    Else
      ff = IO.Directory.GetFiles(pszFolder, "*.lnk", IO.SearchOption.AllDirectories)
    End If
    For Each f As String In ff
      Dim sTarget As String = GetShortcutTarget(f)
      If Strings.Len(sTarget) > 0 Then
        If bInTheMiddle Then
          If (InStr(UCase(sTarget), UCase(pszTargetName)) > 0) Then Return f
        Else
          If UCase(IO.Path.GetFileName(sTarget)) = UCase(pszTargetName) Then Return f
        End If
      End If
    Next
    Return ""
  End Function


  Public Function GetShortcutTarget(ByVal pszShortcutPath As String) As String
    'путь к файлу, на кот. указывает ярлык
    Try
      Dim link As New ShellLink()
      DirectCast(link, IPersistFile).Load(pszShortcutPath, STGM_READ)
      Dim sb As New StringBuilder(MAX_PATH)
      Dim data As New WIN32_FIND_DATA
      DirectCast(link, IShellLinkW).GetPath(sb, sb.Capacity, data, 0)
      Return sb.ToString()
    Catch
      Return ""
    End Try
  End Function


Смысл сказанного в первом посте, что простое Copy не справляется с "Локализацией", будет "Fax and Scan"
А вот SHFileOperation (по сути аналог переноса ручками) очень даже справляется, будет "Факсы и сканирование"
Кажется есть в .Net другой класс, не IO.File.Copy, который надстройка над SHFileOperation (с прогрессами и корзинами если хочется), но просто уже не охота копаться и вспоминать.

Cat2Ведь в классе управлении службами System.ServiceProcess свойство StartType все же было реализовано в NetFramework 4.6! Не прошло и 20 лет!
До этого надо было читать реестр.

Я так делаю:

Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
  Public Function SetServiceAutoStart(ByVal ServiceName As String, ByVal bAutoStart As Boolean) As Boolean
    'admin
    SetServiceAutoStart = False
    ' Get a handle to the SCM database. 
    Dim schSCManager As IntPtr = OpenSCManager(vbNullString, vbNullString, SC_MANAGER_ALL_ACCESS)
    If schSCManager = IntPtr.Zero Then
      'Debug.Print("OpenSCManager failed: " & RaiseAPIErrorByNumber(Err.LastDllError))
      Exit Function
    End If

    ' Get a handle to the service.
    Dim schService As IntPtr = OpenService(schSCManager, ServiceName, SERVICE_CHANGE_CONFIG)
    If schService = IntPtr.Zero Then
      'Debug.Print("OpenService failed: " & RaiseAPIErrorByNumber(Err.LastDllError))
      CloseServiceHandle(schSCManager)
      Exit Function
    End If
    ' Change the service AutoStart
    If ChangeServiceConfig(schService, SERVICE_NO_CHANGE, _
     IIf(bAutoStart, SERVICE_AUTO_START, SERVICE_DEMAND_START), SERVICE_NO_CHANGE) = False Then
      'Debug.Print("ChangeServiceConfig failed: " & RaiseAPIErrorByNumber(Err.LastDllError))
    Else
      'Debug.Print("Service AutoStart successfully changed to " & bAutoStart.ToString)
      SetServiceAutoStart = True
    End If

    CloseServiceHandle(schService)
    CloseServiceHandle(schSCManager)
  End Function

  Public Function GetServiceStartType(ByVal ServiceName As String) As Integer
    ' It returns zero value on error
    'возвращает тип автозапуска: 2-SERVICE_AUTO_START;3-SERVICE_DEMAND_START;4-SERVICE_DISABLED
    Dim hService As IntPtr
    Dim r As Integer, SCfg As QUERY_SERVICE_CONFIG
    Dim pBuffer As IntPtr

    GetServiceStartType = 0
    Dim hSCManager As IntPtr = OpenSCManager(vbNullString, vbNullString, SC_MANAGER_CONNECT)
    If hSCManager <> IntPtr.Zero Then
      hService = OpenService(hSCManager, ServiceName, SERVICE_QUERY_CONFIG)
      If hService <> IntPtr.Zero Then
        If QueryServiceConfig(hService, pBuffer, r, r) = False Then
          If Err.LastDllError = ERROR_INSUFFICIENT_BUFFER Then
            pBuffer = Marshal.AllocHGlobal(r)
            If QueryServiceConfig(hService, pBuffer, r, r) Then
              SCfg = Marshal.PtrToStructure(pBuffer, GetType(QUERY_SERVICE_CONFIG))
              GetServiceStartType = SCfg.dwStartType
            End If
          End If
        End If
        CloseServiceHandle(hService)
      End If
      CloseServiceHandle(hSCManager)
    End If
    If Not pBuffer.Equals(0) Then
      Marshal.FreeHGlobal(pBuffer)
    End If
  End Function



А раньше вообще не парился:

Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
  Public Sub SetServiceAutoStart_SC(ByVal ServiceName As String, ByVal bAutoStart As Boolean)
    'admin
    If bAutoStart Then
      ShellAndContinueNet("sc config " & ServiceName & " start= auto", AppWinStyle.Hide) 'vbNormalFocus
    Else
      ShellAndContinueNet("sc config " & ServiceName & " start= demand", AppWinStyle.Hide) 'vbNormalFocus
    End If
  End Sub



Cat2в NetFramework 4.6
Я сижу в .Net 4.5, причем стараюсь делать .Net 2.0 совместимый код (дублирование под XP, жаба душит отказаться от этой "поддержки", уж очень наработки хорошие, "дорог как память").
А посему даже SpecialFolder.CommonDesktopDirectory и SpecialFolder.CommonPrograms пришлось делать через SHGetFolderPath (ну там несколько аналогов этой ф-ции есть, смысл в наборе CSIDL_)
Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
Public Function GetCommonDesktopDirectoryPath() As String
    'Return Environment.GetFolderPath(Environment.SpecialFolder.CommonDesktopDirectory) 'не поддерживается в .Net ниже версии 4
    Return GetSysFolderPath(CSIDL_VALUES.CSIDL_COMMON_DESKTOPDIRECTORY)
  End Function

  Public Function GetCommonProgramsPath() As String
    'Return Environment.GetFolderPath(Environment.SpecialFolder.CommonPrograms) 'не поддерживается в .Net ниже версии 4
    Return GetSysFolderPath(CSIDL_VALUES.CSIDL_COMMON_PROGRAMS)
  End Function

  Public Function GetCommonAdminToolsPath() As String
    'Return Environment.GetFolderPath(Environment.SpecialFolder.CommonAdminTools) 'не поддерживается в .Net ниже версии 4
    Return GetSysFolderPath(CSIDL_VALUES.CSIDL_COMMON_ADMINTOOLS)
  End Function

  Private Function GetSysFolderPath(ByVal CSIDL As CSIDL_VALUES) As String

    GetSysFolderPath = ""

    ' Create buffer for return results.
    Dim buffer As String = Space(MAX_PATH)

    ' Grab requested system folder.
    If SHGetFolderPath(IntPtr.Zero, CSIDL, IntPtr.Zero, SHGFP_TYPE_DEFAULT, buffer) = S_OK Then
      GetSysFolderPath = Strings.Left(buffer, InStr(buffer & vbNullChar, vbNullChar) - 1)
    End If
  End Function

...
Рейтинг: 0 / 0
3 сообщений из 3, страница 1 из 1
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Разное поведение при копировании ярлыков
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]