March 28, 2024, 03:31:24 AM

News:

Own IWBasic 2.x ? -----> Get your free upgrade to 3.x now.........


Get description of an exe file

Started by Andy, February 17, 2014, 12:00:27 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Andy

Hi,

I'm working on an updated version of the "Alternative task manager" which I posted a few days ago.

The new version allows you to sort the processes alhabetically, but it would be nice to have the description
of each process as well.

eg:

Adobe.exe      Process ID    -  "Adobe reader"
notepad.exe   Process ID    - "Notepad"

How can I get the description "Adobe reader" or any description for whatever exe is running?

There are API's like GetFileVersioninfo etc, frankly i'm not sure how to use these or even if that's the right one.

Can anyone help with this - an example would be good.

PS - I've added how to sort an array alphabetically in user offerings section.

Thanks,
Andy.
Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

LarryMc

I was able to track down two pieces of info.
First, in your task manager you are getting the base name of the file for processes.
You'll need to modify your code so it also gets the fullpath name.
I plugged this into your code and got some of the complete paths
string lpFilename=space$(255)
hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE,pe.th32ProcessID)
GetModuleFileNameEx(hProcess,0,lpFilename,len(lpFilename))

a lot of them I just got one character - I don't know if it's a wstring issue or what.

2nd I found this sub routine.
If you can get it converted it will do what you want.



/*
GetInfo("Comments");
GetInfo("CompanyName");
GetInfo("FileDescription");
GetInfo("FileVersion");
GetInfo("InternalName");
GetInfo("LegalCopyright");
GetInfo("LegalTrademarks");
GetInfo("OriginalFilename");
GetInfo("PrivateBuild");
GetInfo("ProductName");
GetInfo("ProductVersion");
*/

char *GetInfo(char *InfoItem)
{
    static     char    szResult[256] = {0};
    char    szFullPath[256];
    char    szGetName[256];
    LPSTR   lpVersion;        // String pointer to Item text
    DWORD   dwVerInfoSize;    // Size of version information block
    DWORD   dwVerHnd=0;        // An 'ignored' parameter, always '0'
    UINT    uVersionLen;
    BOOL    bRetCode;

    GetModuleFileName (NULL, szFullPath, sizeof(szFullPath));
    dwVerInfoSize = GetFileVersionInfoSize(szFullPath, &dwVerHnd);
    if (dwVerInfoSize) {
        LPSTR   lpstrVffInfo;
        HANDLE  hMem;
        hMem = GlobalAlloc(GMEM_MOVEABLE, dwVerInfoSize);
        lpstrVffInfo  =  (LPSTR)GlobalLock(hMem);
        GetFileVersionInfo(szFullPath, dwVerHnd, dwVerInfoSize, lpstrVffInfo);

        // Get a codepage from base_file_info_sctructure

        lstrcpy(szGetName, "\\VarFileInfo\\Translation");
        uVersionLen   = 0;
        lpVersion     = NULL;
        bRetCode = VerQueryValue((LPVOID)lpstrVffInfo,
               (LPSTR)szGetName,
               (void **)&lpVersion,
               (UINT *)&uVersionLen);
        if ( bRetCode && uVersionLen && lpVersion) {
            sprintf(szResult, "%04x%04x", (WORD)(*((DWORD *)lpVersion)),
                (WORD)(*((DWORD *)lpVersion)>>16));
//            lstrcpy(szResult, lpVersion);
        }
        else {
            // 041904b0 is a very common one, because it means:
            //   US English/Russia, Windows MultiLingual characterset
            // Or to pull it all apart:
            // 04------        = SUBLANG_ENGLISH_USA
            // --09----        = LANG_ENGLISH
            // --19----        = LANG_RUSSIA
            // ----04b0 = 1200 = Codepage for Windows:Multilingual
            lstrcpy(szResult, "041904b0");
        }

        // Add a codepage to base_file_info_sctructure

        sprintf (szGetName, "\\StringFileInfo\\%s\\", szResult);
        // Get a specific item
        lstrcat (szGetName, InfoItem);
        uVersionLen   = 0;
        lpVersion     = NULL;
        bRetCode = VerQueryValue((LPVOID)lpstrVffInfo,
               (LPSTR)szGetName,
               (void **)&lpVersion,
               (UINT *)&uVersionLen);
        if ( bRetCode && uVersionLen && lpVersion) {
            lstrcpy(szResult, lpVersion);
        }
        else {
            lstrcpy(szResult, "");
        }
    }
    return szResult;
}


hope this helps a little
LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

Andy

Thanks Larry for that,

Will try to figure it out if I can.

meanwhile, I've got a little further - see attached.

I can get the full path and can use GetFileVersionInfoSize but i'm now struggling to use
GetFileVersionInfo which I think is the next step.

Thanks,
Andy.
Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

Andy

Some things I have found:

1. Winver.inc has the API's needed to do what I want.
2. Found an example of how to get the version number of a file - modified for "Notepad".
3. Found the "Structures" of "String", "StringFileInfo","StringTable" needed.

Not sure if I have got these right? probably not:
changed DWORD to UINT
changed WCHAR to WSTRING

Here is a link to the MSDN pages
http://msdn.microsoft.com/en-us/library/windows/desktop/ms646992%28v=vs.85%29.aspx

Attached is the modified example
Thanks,
Andy.
 
Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

LarryMc

I played with the example and added some code that should work but doesn't.
LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

Andy

Thanks Larry,

Yes it failed on my PC as well.

Will have a better look at it and try to see why.

Thanks.
Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

LarryMc

Partial success
pointer pbuf=new(wstring,1)
int plen=0
IF(VerQueryValue(pVer,L"\\StringFileInfo\\040904E4\\FileDescription",pbuf,plen))
print "success"
print#<wstring>pbuf,plen
else
print "failure"
endif

This will print success
plen is 52
but it only prints two hidden characters for the FileDescription
LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

Andy

Hi Larry,

Sorry I've had a bad PC day today.

Re: hidden characters.

Yes it does seem to return 2 hidden ones.

I thought this might be easy, getting the exe description - I now feel like Alice down the rabbit hole!

"pbuf" maybe is an address of a pointer ?

http://msdn.microsoft.com/en-us/library/windows/desktop/ms647464%28v=vs.85%29.aspx

If that helps any - I'm now completely lost with this.
:)



Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

Andy

Just had an idea:

I can search through the "Uninstall" section of the registry, the folders there contain "most" of the installed
applications together with the exe file and a "description" eg: "Adobe Reader" etc.

I have the process exe file names, so it would just be a matter of scanning the "uninstall" folder, finding a
match to the exe file and then get the "description".

This may not be 100%, but I think it will get almost all the application names.

Andy.
:) 
Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

LarryMc

I kept hoping someone who knew c++ would help us out.
I'd settle for a .lib (written in anything) with functions to get the info.  There's plenty of c examples around that does that.

LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

Andy

Larry,

I found this site that says it can be done in VB6

http://www.planet-source-code.com/vb/scripts/ShowCode.asp?txtCodeId=4976&lngWId=1

VB6 is close in structure to IWB, but i'm not sure how to convert it.

Andy.
Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

LarryMc

Well, I pestered it into submission.
I spent a lot of time studying the info in a compiled VersionInfo resource file.
It is a binary file that contains WORD, DWORD, and variable length WSTRINGs that have padding of WSTRING NULLS to stretch to 32 bit boundaries.  What all that means is that there is no nice, neat structure to read like a binary file that contains fixed length records of a given UDT.

Anyway, I come up with 2 programs.
One reads the fixed file info data.
We already had some working code that gave us two pieces of data.
In the subroutine I expanded it to give us some additional info when it is available.

The other program handles what I couldn't get to work with the API.
It does a lot of point math to get to a location where the data should be and returns all the available in a UDT.

The short coming is that it reads the first block of text it encounters and total ignores the language and codepage.
But, all the ones I looked at had only English text.

Feel free to use the code if it will do you any good and if you feel a need to improve it and are able to then please share with the forum.

Maybe this will work until someone comes along that can make the API function work properly.
LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

Andy


Larry,

That's great! - thanks for working on it!!

Just adding it to a new version of the alternative task manager and will post it as soon as I am done.

It does get the details, but not all because the authors of some code don't fill in the company name etc.

Thanks so much,
Andy.
:)
Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

LarryMc

Quote from: andy1966 on March 04, 2014, 06:52:01 AM

Larry,

That's great! - thanks for working on it!!

Just adding it to a new version of the alternative task manager and will post it as soon as I am done.

It does get the details, but not all because the authors of some code don't fill in the company name etc.

Thanks so much,
Andy.
:)

Did you look at the Fixed version too?  It adds additional text that we haven't seen in any of our previous postings.
LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

Andy

Hi Larry,

Yes I did look at the Fixed version you posted.

I've included both into a new (unfinished version) of the alternative task manager.

At the moment it takes a "snapshot" of what processes are running i.e. it's not updating at the moment.
Please see the attachment, sorry if it's a bit of a mess at the momment - not the final version.

Click on the "Get file details" button when you have clicked on a process name in the list.

One small silly question - how do I get horizontal scroll bars to appear - i've tried adding @HSCROLL but it doesn't seem to appear.

CONTROL dy,@LISTBOX,"",10,90,200,300,@CTLISTNOTIFY,747 - Know i'm missing something simple.

Thanks,
Andy.

Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

LarryMc

okay, I fixed several things I found.
Since you asked about the horizontal scroll bar I will start with that.

First, in order to have a horiz scroll bar the Listbox has to be created with the @HSCROLL flag.
In order make the LB scroll the right amount you have to determine the length of the longest line and then set the extents with SETHORIZEXTENT.  I added code to do that(since that code needs a window to do the sizing and the font of the window to match the font of the text I changed the font of dy)
But that leaves us with an appearance problem.  Since the horizontal scroll bar disappears when there is no line longer than the width of the LB,, we could wind up with 747 having no SB, 748 with no SB and 749 with a SB.  Since the SB takes up roughly one line in the LB that means you'd only be able to see part of the last visible entry.  So, we need a way to have the SB always show in all 3 LBs and just disable the SB if it isn't needed(it will never be needed in 748.
Fortunately there is a style flag to do that LBS_DISABLENOSCROLL
With the SB now present the bottom line was being clipped so I made 5 pixel adjustment where necessary.
So that takes care of the horiz scroll issues.

Now for the others

1.I noticed a flicker everytime the dy,dy2, or dy3 window is opened.  That's because you have your CENTERWINDOW command right after you create the window.  To get rid of that always put your CENTERWINDOW command in the message handler und @IDCREATE and you'll never see the flicjker.  I fixed that

2. I noticed that the vertical SB worked only if you used the drag button. I added the code to make the line up/dn and page up/down clicks move the scroll also.

3. Just for the heck of it I added code so that if you double click an entry in 747,748, or 749 it will open dy3

4. I noticed that you are creating controls and then hiding them right afterCONTROL dy,@LISTBOX,"",640,90,200,300,@CTLISTNOTIFY,750
SHOWWINDOW dy,@SWHIDE,750

CONTROL dy,@static,"",500,20,20,25,@CTLISTNOTIFY,801
CONTROL dy,@static,"",540,20,20,25,@CTLISTNOTIFY,802
CONTROL dy,@static,"",580,20,20,25,@CTLISTNOTIFY,803
SHOWWINDOW dy,@SWHIDE,801
SHOWWINDOW dy,@SWHIDE,802
SHOWWINDOW dy,@SWHIDE,803

If you do that with very many controls you'll start to get  flicker like with the window centering.

I didn't change your code but suggest when you want to create hidden controls you do it this way
CONTROL dy,@LISTBOX,"",640,90,200,300,@CTLISTNOTIFY|@SYSMENU,750
CONTROL dy,@static,"",500,20,20,25,@CTLISTNOTIFY|@SYSMENU,801
CONTROL dy,@static,"",540,20,20,25,@CTLISTNOTIFY|@SYSMENU,802
CONTROL dy,@static,"",580,20,20,25,@CTLISTNOTIFY|@SYSMENU,803

@HIDDEN which works for windows doesn't work on controls. Since the value @SYSMENU is not used as a style flag for any control it was just a handy constant to use in the CONTROL command to reset the extended-style visibility flag.

As before I have identified lines and blocks of code I modified with '<========
LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

Andy

Larry,

Thanks for going through the code and making the changes!

I will post a new version of the "alternatice task manager" in the user offerings section in a few minutes.

once again,
thanks for the hard work,
Andy.
:)
Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

fasecero

Hey, not sure if I've never seen this post, or if I saw it but I could not get it to work. Anyway, I need to get the info from a few filenames. This post was of great help for me, and with more info from the web it seems that I got it to work, in my own codepage language, I'm not sure about the others.

I would like to know if someone can check if it works correctly in a native English OS (different codepage) and maybe some other language would be great, so I can be sure that it works anywhere. Just select a file and compare the Details window info with the messagebox.



$DEFINE UNICODE
$INCLUDE "windowssdk.inc"

' runtime func
DECLARE EXTERN swprintf(POINTER p, POINTER p, ...), INT

' string buffer size
CONST STRING_SIZE = 500

' custom struct
TYPE FILE_INFO
IWSTRING fullpath[STRING_SIZE]
IWSTRING FileDescription[STRING_SIZE]
IWSTRING FileVersion[STRING_SIZE]
IWSTRING InternalName[STRING_SIZE]
IWSTRING CompanyName[STRING_SIZE]
IWSTRING LegalCopyright[STRING_SIZE]
IWSTRING OriginalFilename[STRING_SIZE]
IWSTRING ProductName[STRING_SIZE]
IWSTRING ProductVersion[STRING_SIZE]

BOOL ok
wstring strcharset
UINT nQuerySize
LPBYTE  m_lpVersionData
ENDTYPE

' interface
CONST EDIT_PATH = 1
CONST BUTTON_SELECT = 2
CONST BUTTON_WINDOW = 3
CONST BUTTON_WINAPI = 4
DIALOG d1
CREATEDIALOG d1,0,0,609,155,0x80C80080,0,"File Info",&d1_handler
CONTROL d1,@EDIT,"Please select a filename",16,16,377,18,0x50800000,EDIT_PATH
CONTROL d1,@SYSBUTTON,"Select File",406,11,181,27,0x50000000,BUTTON_SELECT
CONTROL d1,@SYSBUTTON,"Show File Details Window",58,71,198,62,0x50000000,BUTTON_WINDOW
CONTROL d1,@SYSBUTTON,"Show File Details From WINAPI",312,72,218,60,0x50000000,BUTTON_WINAPI

' variables
INT fileSelected = 0
ISTRING filename[STRING_SIZE]

' entry point
DOMODAL d1

' procedure
SUB d1_handler
SELECT @MESSAGE
CASE @IDINITDIALOG
OnInit()
CASE @IDCLOSEWINDOW
OnClose()
CASE @IDCONTROL
SELECT @CONTROLID
CASE BUTTON_SELECT
IF @NOTIFYCODE = 0
OnSelectFile()
ENDIF
CASE BUTTON_WINDOW
IF @NOTIFYCODE = 0
OnShowDetailsWindow()
ENDIF
CASE BUTTON_WINAPI
IF @NOTIFYCODE = 0
OnShowWinapiMessageBox()
ENDIF
ENDSELECT
ENDSELECT
RETURN
ENDSUB

' ------------------------------------------------------------------------------------
' EVENTS
' ------------------------------------------------------------------------------------

SUB OnInit()
OleInitialize(0)
CENTERWINDOW d1
UpdateGUI()
ENDSUB

SUB OnClose()
OleUninitialize()
CLOSEDIALOG d1,@IDOK
ENDSUB

SUB OnSelectFile()
STRING filter = "Executable Files (*.exe)|*.exe"

filename = FILEREQUEST("Select File", 0, 1, filter, "*.*", 0, "")

IF LEN (filename) THEN
fileSelected = 1
SETCONTROLTEXT d1, EDIT_PATH, filename
UpdateGUI()
ENDIF
ENDSUB

SUB OnShowDetailsWindow()
SHELLEXECUTEINFO info

IWSTRING unicode_filename[STRING_SIZE] = S2W(filename)

info.cbSize = LEN(info)
info.lpFile = &unicode_filename
info.nShow = SW_SHOW
info.fMask = SEE_MASK_INVOKEIDLIST
info.lpVerb = L"properties"
info.lpParameters = L"details"

IF ShellExecuteEx(&info) THEN
ELSE
PrintLastError()
ENDIF
ENDSUB

SUB OnShowWinapiMessageBox()
FILE_INFO info

IWSTRING unicode_filename[STRING_SIZE] = S2W(filename)
FileInfoInit(info, unicode_filename)
FileInfoFillData(info)

IWSTRING textInfo[STRING_SIZE]
textInfo = L"File Description: " + info.FileDescription + WCHR$(10)+ WCHR$(10)
textInfo += L"File Version: " + info.FileVersion + WCHR$(10)
textInfo += L"Product Name: " + info.ProductName + WCHR$(10)
textInfo += L"Product Version: " + info.ProductVersion + WCHR$(10)
textInfo += L"Copyright: " + info.LegalCopyright + WCHR$(10)+ WCHR$(10)
textInfo += L"Original Filename: " + info.OriginalFilename + WCHR$(10)+ WCHR$(10)
textInfo += L"Internal Name: " + info.InternalName + WCHR$(10)
textInfo += L"Company Name: " + info.CompanyName + WCHR$(10)
_MessageBox(0, textInfo, L"File Details", 0)

FileInfoFinish(info)
ENDSUB

' ------------------------------------------------------------------------------------
' INTERFACE FUNCTIONS
' ------------------------------------------------------------------------------------

SUB UpdateGUI()
ENABLECONTROL d1, EDIT_PATH, 0
ENABLECONTROL d1, BUTTON_WINDOW, fileSelected
ENABLECONTROL d1, BUTTON_WINAPI, fileSelected
ENDSUB

' ------------------------------------------------------------------------------------
' AUX FUNCIONS
' ------------------------------------------------------------------------------------

SUB CopyString(pointer buffer, pointer source, INT buffcapacity)
int lenght = wcslen(source)
if lenght > buffcapacity THEN lenght = buffcapacity
wcsncpy(buffer, source, lenght + 1)
ENDSUB

SUB PrintLastError(), INT
uint _Erro = 0
uint nSize = 0
uint Arguments = 0
POINTER ErMes = 0

_Erro = GetLastError()
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,0, _Erro,0, &ErMes,nSize,Arguments)
IF _Erro > 0 THEN _MessageBox(0, ErMes, L"Error: " + WSTR$(_Erro), 0)

LocalFree(ErMes)

RETURN _Erro
ENDSUB

' ------------------------------------------------------------------------------------
' FILE INFO
' ------------------------------------------------------------------------------------

SUB FileInfoInit(FILE_INFO info, wstring fullpath, OPT INT dwLangCharset = 0)
DWORD dwHandle
    DWORD   m_dwLangCharset

ZeroMemory(info, LEN(info))
info.fullpath = fullpath
info.ok = 0

DWORD dwDataSize = GetFileVersionInfoSize(fullpath, &dwHandle)

IF dwDataSize THEN
info.m_lpVersionData = LocalAlloc(LPTR, dwDataSize)

IF GetFileVersionInfo(fullpath, dwHandle, dwDataSize, info.m_lpVersionData) THEN
pointer pTransTable

IF VerQueryValue(info.m_lpVersionData, L"\VarFileInfo\Translation", &pTransTable, &info.nQuerySize) THEN
m_dwLangCharset = MAKELONG(HIWORD(*<POINTER>pTransTable), LOWORD(*<POINTER>pTransTable))

int charset = dwLangCharset
IF charset = 0 THEN charset = m_dwLangCharset

swprintf( info.strcharset, L"%08X", charset )

info.ok = 1
ENDIF
ENDIF
ENDIF
ENDSUB

SUB FileInfoGetValueData(FILE_INFO info, wstring buffer, INT maxBuffLen, wstring valueData)
IF info.ok THEN
WSTRING strBlockName = L"\StringFileInfo\"+ info.strcharset + L"\" + valueData
pointer lpData = 0

IF VerQueryValue(info.m_lpVersionData, strBlockName, &lpData, &info.nQuerySize) THEN
CopyString(buffer, lpData, maxBuffLen)
ENDIF
ENDIF
ENDSUB

SUB FileInfoFillData(FILE_INFO info)
IF info.ok THEN
FileInfoGetValueData(info, info.FileDescription, STRING_SIZE, L"FileDescription")
FileInfoGetValueData(info, info.FileVersion, STRING_SIZE, L"FileVersion")
FileInfoGetValueData(info, info.InternalName, STRING_SIZE, L"InternalName")
FileInfoGetValueData(info, info.CompanyName, STRING_SIZE, L"CompanyName")
FileInfoGetValueData(info, info.LegalCopyright, STRING_SIZE, L"LegalCopyright")
FileInfoGetValueData(info, info.OriginalFilename, STRING_SIZE, L"OriginalFilename")
FileInfoGetValueData(info, info.ProductName, STRING_SIZE, L"ProductName")
FileInfoGetValueData(info, info.ProductVersion, STRING_SIZE, L"ProductVersion")
ENDIF
ENDSUB

SUB FileInfoFinish(FILE_INFO info)
IF info.ok THEN
IF info.m_lpVersionData THEN
LocalFree(info.m_lpVersionData)
ENDIF
ENDIF
ENDSUB