Search code examples
c#dllpinvoke

How to extract string resource from DLL


I'm making an application for manage system file extensions, I have a problem.

System extensions like .jpg, .exe, .dll, .png, .txt, etc. has a registry value called FriendlyTypeName, for example, the FriendlyTypeName of a jpeg file is @%SystemRoot%\System32\shell32.dll,-30596. The displayed value depends of the current language.

How to extract the string value from resource id (e.g.: -30596) using C#?. I guess strings can be extracted using p/invoke (i'm not sure).


Solution

  • Resources can be extract using LoadString, LoadIcon and etc. However, the hInstance must be different of your application's hInstance, otherwise, you will only be able to extract resources from your own .exe. If you want to extract any resources from external DLLs like system libraries, you must get the hInstance of the DLL you want to extract by calling LoadLibrary, and call FreeLibrary to finish file usage.

    [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Ansi)]
    private static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)]string lpFileName);
    
    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    private static extern int LoadString(IntPtr hInstance, int ID, StringBuilder lpBuffer, int nBufferMax);
    
    [DllImport("kernel32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool FreeLibrary(IntPtr hModule);
    
    private string ExtractStringFromDLL(string file, int number) {
        IntPtr lib = LoadLibrary(file);
        StringBuilder result = new StringBuilder(2048);
        LoadString(lib, number, result, result.Capacity);
        FreeLibrary(lib);
        return result.ToString();
    }
    

    StringBuilder max capacity is 2048 (if you wish you can change the value).

    Here's an example:

    string loadedString = ExtractStringFromDLL("shell32.dll", 30596);
    Debug.Write(loadedString);
    

    Windows' default relative path is %SystemRoot%\system32 and there's not need to include the full path unless you're extracting the string from non-system DLLs.

    Don't forget to delete the - symbol from resource number because negative numbers means resource ID for FriendlyTypeName and LoadString requires positive numbers as resource ID.

    EDIT: You can also extract resources from .exe files and any file that contains resources.