Sign in to follow this  
Followers 0
Terenz

Shortcut icon ( but from file )

15 posts in this topic

#1 ·  Posted (edited)

I have some problem to find a solution for this, hope you guys has an idea.

Pratically:

1) Create a shortcut of a text file ( it can be anything, not only a text file )

2) Get the icon of that shortcut

The main problem is number 2, how i can get the icon from the shortcut of a file? With the build in not work, i have empty value for [4]

;~ FileCreateShortcut(@ScriptDir & "\Text.txt", @DesktopDir & "\TEXT.LINK", @DesktopDir, "")
$aShort = FileGetShortcut(@DesktopDir & "\TEXT_LINK.lnk")
If IsArray($aShort) Then
    MsgBox(0, 0, $aShort[4])
    MsgBox(0, 0, $aShort[5])
EndIf

After i get the executable and the icon index, i need to:

3) Change the path of the shortcut ( like anothereditor.exe Text.txt )

4) Use the icon from number two ( because if i don't change the icon it will use the anothereditor.exe icon and i don't what it )

So my problem is only one, how to get the executable-icon index from a shortcut of a file.

Thanks

Edited by Terenz

Nothing is so strong as gentleness. Nothing is so gentle as real strength

 

Share this post


Link to post
Share on other sites



#2 ·  Posted (edited)

i made something in c# for extracting icon's i can't get it to work in autoit

script

using System;
using System.IO;
using System.Threading;
using System.Drawing;
using System.Runtime.InteropServices;

namespace Icon_extractor
{
    class Program
    {
        static void Main(string[] args)
        {
            switch (args.Length)
            {
                case 0:
                    uitleg();
                    break;
                case 1:
                    if (args[0] == "/?")
                    {
                        uitleg();
                    }
                    break;
                case 4:
                    Icon myIcon = Getpicture(Convert.ToString(args[0]), Convert.ToBoolean(args[1]));
                    if (Convert.ToBoolean(args[3]))
                    {
                        Bitmap bmp = myIcon.ToBitmap();
                        using (FileStream fs = new FileStream(Convert.ToString(args[2]) + ".bmp", FileMode.Create)) bmp.Save(fs, System.Drawing.Imaging.ImageFormat.Bmp);
                    }
                    else
                    {
                        using (FileStream fs = new FileStream(Convert.ToString(args[2]) + ".ico", FileMode.Create)) myIcon.Save(fs);
                    }
                    break;
            }
        }

        static Icon Getpicture(string fName, Boolean smallicon)
        {
            Shfileinfo shinfo = new Shfileinfo();
            //Use this to get the small Icon
            if (smallicon)
            {
                IntPtr hImgSmall = Win32.SHGetFileInfo(fName, 0, ref shinfo,
                                                       (uint)Marshal.SizeOf(shinfo),
                                                       Win32.ShgfiIcon |
                                                       Win32.ShgfiSmallicon);
            }
            else
            {
                //Use this to get the large Icon
                IntPtr hImgLarge = Win32.SHGetFileInfo(fName, 0,
                                                       ref shinfo, (uint)Marshal.SizeOf(shinfo),
                                                       Win32.ShgfiIcon | Win32.ShgfiLargeicon);
            }
            //The icon is returned in the hIcon member of the shinfo
            //struct
            return Icon.FromHandle(shinfo.hIcon);
        }

        private static void uitleg()
        {
            Console.WriteLine("extract icon to .ico file");
            Console.WriteLine("1st parameter file to extract");
            Console.WriteLine("2de parameter true = small false = big icon");
            Console.WriteLine("3de parameter place and name to save with give no extension");
            Console.WriteLine("3de parameter true = bmp  false = ico");
            Thread.Sleep(10000);
        }
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct Shfileinfo
    {
        public IntPtr hIcon;
        public IntPtr iIcon;
        public uint dwAttributes;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
        public string szDisplayName;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
        public string szTypeName;
    };

    class Win32
    {
        public const uint ShgfiIcon = 0x100;
        public const uint ShgfiLargeicon = 0x0;    // 'Large icon
        public const uint ShgfiSmallicon = 0x1;    // 'Small icon

        [DllImport("shell32.dll")]
        public static extern IntPtr SHGetFileInfo(string pszPath,
                                    uint dwFileAttributes,
                                    ref Shfileinfo psfi,
                                    uint cbSizeFileInfo,
                                    uint uFlags);
    }
}

compile c# script i do with this bat file dir you must change to yours

set oldp=%PATH% 
set PATH=%PATH%;C:\WINDOWS\Microsoft.NET\Framework\v3.5
csc /out:Icon_extractor.exe /win32icon:icon.ico /platform:anycpu program.cs
set PATH=oldp
pause

on autoit i do it this way

If FileExists(@ScriptDir & '\iconsprog\icon.bmp') = 0 Then
Run(@ScriptDir & '\Icon_extractor.exe "' & file to extract & '" False "' & @ScriptDir & '\iconsprog\' & name file bmp & '" true', @ScriptDir, @SW_HIDE)
Do
   Sleep(2 * 1000)
   Until Not ProcessExists("Icon_extractor.exe")
EndIf
$button = GUICtrlCreateButton('this is button', $posl, $post, $bw, $bh, $BS_MULTILINE)
    ; icon before text
    $hImagebtn3 = _GUIImageList_Create(32, 32, 5)
    _GUIImageList_AddBitmap($hImagebtn3, @ScriptDir & '\iconsprog\' & ico file & ".bmp")
    _GUICtrlButton_SetImageList($button, $hImagebtn3)

.bmp is working best in autoit

Edited by Spider001

Share this post


Link to post
Share on other sites

Thanks but i don't think i'll use your solution. I don't need to extract the icon for use it in a shortcut, i'd like the shortcut use the icon registered for that extension.


Nothing is so strong as gentleness. Nothing is so gentle as real strength

 

Share this post


Link to post
Share on other sites

#4 ·  Posted (edited)

Try with this (it looks into the registry) :

#Include <Array.au3> ; Just for _ArrayDisplay()

$aIcon = _GetDefaultIcon(".txt")
_ArrayDisplay($aIcon)

Func _GetDefaultIcon($sExt)
    Local $aRet[2]
    If NOT StringRegExp($sExt, "^\.") Then $sExt = "." & $sExt
    
    Local $sFileType = RegRead("HKCR\" & $sExt, "")
    If $sFileType = "" Then Return SetError(1, 0, "")
    
    Local $sDefaultIcon = StringReplace ( RegRead("HKCR\" & $sFileType & "\DefaultIcon", ""), '"', '')
    If $sDefaultIcon = "" Then Return SetError(1, 0, "")
    
    If StringRegExp($sDefaultIcon, ",-?\d+$") Then
        $aRet = StringRegExp($sDefaultIcon, "(.*),(-?\d+)$", 3)
    Else
        $aRet[0] = $sDefaultIcon
        $aRet[1] = 0
    EndIf
    
    ; Replaces each environment variable by its expanded value
    $aRet[0] = _ExpandEnvStrings($aRet[0])
    Return $aRet
EndFunc


Func _ExpandEnvStrings($sString)
    Local $aVars = StringRegExp($sString, "%([^%]+)%", 3)
    Local $iCount = 0
 
    If IsArray($aVars) Then
        For $i = 0 To UBound($aVars) - 1
            $sVal = EnvGet($aVars[$i])
            If $sVal <> "" Then
                $sString = StringReplace($sString, "%" & $aVars[$i] & "%", $sVal )
                $iCount += 1
            EndIf
        Next
        SetExtended( $iCount )
    Else
        SetExtended(0)
    EndIf
 
    Return $sString
EndFunc
Edited by jguinch

Share this post


Link to post
Share on other sites

Partially work me, 0 is empty and 1 is equal to -102


Nothing is so strong as gentleness. Nothing is so gentle as real strength

 

Share this post


Link to post
Share on other sites

#7 ·  Posted (edited)

Just copy-paste your example. I don't have see the ConsoleWrite :D

The console is correct:

%SystemRoot%\system32\imageres.dll,-102

But the $aRet[0] = Execute i think has some problem in it because in the arraydisplay i don't see nothing for 0

EDIT: Insted of all that Execute, a simply StringSplit with the comma don't give the same result? Why we need to expand that string?

FileCreateShortcut(@ScriptDir & "\Text.txt", @DesktopDir & "\TEXT.LINK", @DesktopDir, "", "", "%SystemRoot%\system32\imageres.dll", "", "-102", @SW_SHOW)
Edited by Terenz

Nothing is so strong as gentleness. Nothing is so gentle as real strength

 

Share this post


Link to post
Share on other sites

#9 ·  Posted (edited)

Work, good.

I think you need just add a 0 in [1] for the extension without comma, like "au3" or in that case [1] is equal to nothing:

; etc    
   Else
        $aRet[0] = $sDefaultIcon
        $aRet[1] = 0
; etc

Or

Local $aRet[2] = [0,0]

Can you answer my question, "Why we need to expand that string?" I'm here to learn :)

Edited by Terenz

Nothing is so strong as gentleness. Nothing is so gentle as real strength

 

Share this post


Link to post
Share on other sites

#10 ·  Posted (edited)

OK, I make made the modification.

For you question : because for some extensions, the registry entry uses an environment variable. For example, on my computer, the value in HKEY_CLASSES_ROOTtxtfileDefaultIcon is %SystemRoot%system32imageres.dll,-102.

Autoit do not see %SystemRoot%  as a valid path, so we have to either expand the value (like I did, or with an other function), or use an AutoIt option (AutoItSetOption)

Edit : if you want to have the real value, uncomment the _ExpandEnvStrings line.

I'm curious to see what other members will offer .. (WinAPI way ?)

Edited by jguinch

Share this post


Link to post
Share on other sites

#11 ·  Posted (edited)

The WINAPI way is SHGetFileInfo + SHGFI_ICONLOCATION but seems not work well, anyway my knowledge of struct is limited. If there aren't better alternative i'll put the thread as solved. Thank you for the explaination ;)

Edited by Terenz

Nothing is so strong as gentleness. Nothing is so gentle as real strength

 

Share this post


Link to post
Share on other sites

#12 ·  Posted (edited)

jguinch i have a problem, check this:

$aIcon = _GetDefaultIcon("rtf")
;[0]|"C:\Program Files (x86)\Windows NT\Accessories\WORDPAD.EXE"
;[1]|1

; Not work
FileCreateShortcut("", @DesktopDir & "\RTF1.lnk", "", '"' & @DesktopDir & '\Test.rtf' & '"', "", $aIcon[0], "", $aIcon[1], @SW_SHOW)

; This work
FileCreateShortcut("", @DesktopDir & "\RTF2.lnk", "", '"' & @DesktopDir & '\Test.rtf' & '"', "", "C:\Program Files (x86)\Windows NT\Accessories\WORDPAD.EXE", "", "1", @SW_SHOW)

Result:

2l9k18o.png

My OS is x64 but i don't think is that the issue, probably is a stupid thing but i can't see any error  :sweating:

Edited by Terenz

Nothing is so strong as gentleness. Nothing is so gentle as real strength

 

Share this post


Link to post
Share on other sites

Confirmed, work. I didn't notice the extra quote from the return value :D

Thanks again


Nothing is so strong as gentleness. Nothing is so gentle as real strength

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0