NO

Author Topic: MS Help 3 testing  (Read 5596 times)

Offline TimoVJL

  • Global Moderator
  • Member
  • *****
  • Posts: 2115
MS Help 3 testing
« on: November 26, 2015, 06:00:52 PM »
Have anyone done MS Help 3 file testing ?
Are those suitable for local help.
Anyone analyzed .mshi files ?
May the source be with you

Offline jj2007

  • Member
  • *
  • Posts: 536
Re: MS Help 3 testing
« Reply #1 on: November 27, 2015, 09:03:39 PM »
You mean e.g. C:\ProgramData\Microsoft\HelpLibrary\catalogs\VS\100\EN-US\VS_100_EN-US_Cat_635839648792475984.1.mshi ?

I have managed to integrate the offline Visual Studio help library into my editor (Your opinion on external references in CHM files); but it was not straightforward, and it relies on somewhat undocumented features. It works fine, though, and having offline access to a GigaByte of Windows help is nice.

But you mean the newest version, apparently. What is better in MS Help 3?

P.S.: This is how my implementation works. Select a word, click Help/VS Help, see the browser open:

Offline TimoVJL

  • Global Moderator
  • Member
  • *****
  • Posts: 2115
Re: MS Help 3 testing
« Reply #2 on: November 27, 2015, 10:58:35 PM »
I am after install free, local usage. Not with that MS Help server.
I like to create help index in local SQLite database and cut crap off.
.mshi is funny file. Total mess and bad design and bad documentation;)

MS Help 3 is that you are using in that picture?
Are those help pages good?
May the source be with you

Offline jj2007

  • Member
  • *
  • Posts: 536
Re: MS Help 3 testing
« Reply #3 on: November 28, 2015, 01:40:53 AM »
MS Help 3 is that you are using in that picture?
Are those help pages good?

I guess it's the previous version. I have the free Visual C++ 2010 Express installed, which has under Help/Manage help settings an option to download the whole MSDN database.

It is free, and the help pages are really good - the original MSDN help pages but offline. The tricky thing was to convince the help library to work without launching that ugly behemoth of Visual Crap  8)

Offline TimoVJL

  • Global Moderator
  • Member
  • *****
  • Posts: 2115
Re: MS Help 3 testing
« Reply #4 on: November 28, 2015, 02:19:15 AM »
2010 -> 2012 -> index-file differs. So moving target >:( It so M$ ???
Their work is not finished
Code: [Select]
R9900.htm VS|winui|~\winui\windowsuserinterface\userinput\mouseinput\mouseinputreference\mouseinputmessages\wm_ncxbuttondblclk.htm WM_NCXBUTTONDBLCLK XBUTTON2
R9901.htm 683c3ad8-0236-474e-a16d-6164c2244cfb IAnalysisRegion::IntersectsWith
WinUI is not converted yet, still using long refs :(
Newer stuff use that short form.
Think how much space are saved in files after that and refs are constant length ;)

Help 3 2010 have less metadata in .mshi than newer ones :(
For example Help.F1 and language are not in first section.
« Last Edit: November 30, 2015, 12:10:44 PM by TimoVJL »
May the source be with you

Offline jj2007

  • Member
  • *
  • Posts: 536
Re: MS Help 3 testing
« Reply #5 on: December 01, 2015, 02:35:07 AM »
2010 -> 2012 -> index-file differs. So moving target >:( It so M$ ???

They make it difficult on purpose 8)

Grincheux

  • Guest
Re: MS Help 3 testing
« Reply #6 on: February 21, 2016, 05:03:15 AM »
use SumatraPdf it reads all help files. That's what I do now.

Offline TimoVJL

  • Global Moderator
  • Member
  • *****
  • Posts: 2115
Re: MS Help 3 testing
« Reply #7 on: February 21, 2016, 10:07:31 AM »
It was MS Help 3 .mshi format, what i was looking for.

EDIT: 2018-09-26
Code: [Select]
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
// Fabrikam_SouthPark_Example.mshi

int main(int argc, char **argv)
{
HANDLE hFrom;
BYTE *pMem, *pP1, *pP2;
DWORD nMax, nRead;
char szTmp[512];

hFrom = CreateFile(argv[1]
, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (hFrom == INVALID_HANDLE_VALUE)
{
printf("error file open\n");
return 1;
}

nMax = GetFileSize(hFrom, NULL);
pMem = LocalAlloc(LPTR, nMax + 1);
ReadFile(hFrom, pMem, nMax, &nRead, NULL);
CloseHandle(hFrom);
*(pMem+nMax)=0;

printf("KeyWds: %Xh\n", *(DWORD*)(pMem+nMax-148));
printf("KeyWds: %Xh\n", *(DWORD*)(pMem+nMax-184));
printf("Files:  %Xh\n", *(DWORD*)(pMem+nMax-400));
BYTE *pP3 = pMem + *(DWORD*)(pMem+nMax-148);
//BYTE *pP3 = pMem + nPosKw;
//BYTE *pP3 = pMem + *(DWORD*)(pMem+nMax-184);
//BYTE *pP3 = pMem + *(DWORD*)(pMem+nMax-400);
int nCount = 0;
do {
pP2 = pP3 + 1;
if (!*pP2 || *pP2 > *pP3) break; // error
lstrcpyn(szTmp, (char*)pP2 + 1, *pP2+1);
printf("%4Xh ", *(WORD*)(pP3+*pP2+2)); // data after string
printf("%s\n", szTmp);
pP3 += *pP3 + 1;
nCount++;
} while (*pP3);
printf("%d\n", nCount);
/* pP1 = pMem+nMax-424;
for (int i=0; i<106; i++) {
printf("%08X %08X\n", pP1-pMem, *(DWORD*)pP1);
pP1 += 4;
}*/
return 0;
}
EDIT 2018-09-29
Code: [Select]
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
// Fabrikam_SouthPark_Example.mshi
// Visual_Studio_20219249_VS_100_en-us_1.mshi
// v2Help_on_Help_B837_VS_110_en-us_1.mshi
char *Mem2HexS(char *pMem, char *pBuf, int nLen);
void ShowFileInfo(BYTE *pMem, BYTE *pPtr, int nCntMax, int nVer);
void ShowInfo(BYTE *pMem, BYTE *pPtr, int nCntMax, int nVer);
char *aName1[],*aName2[];
int main(int argc, char **argv)
{
HANDLE hFrom;
BYTE *pMem, *pP1, *pP2;
DWORD nMax, nRead;
char szTmp[512];

hFrom = CreateFile(argv[1]
, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (hFrom == INVALID_HANDLE_VALUE)
{
printf("error file open\n");
return 1;
}

nMax = GetFileSize(hFrom, NULL);
pMem = LocalAlloc(LPTR, nMax + 1);
ReadFile(hFrom, pMem, nMax, &nRead, NULL);
CloseHandle(hFrom);
*(pMem+nMax)=0;

int nHdrSize = *(DWORD*)(pMem+nMax-4);
int nHdrOfs = *(DWORD*)(pMem+nMax-8);
pP1 = pMem+nHdrOfs;
lstrcpyn(szTmp, (char*)pP1 + 1, *pP1+1);
printf("Tool  version: %s\n", szTmp);
pP1 += *pP1+1;
lstrcpyn(szTmp, (char*)pP1 + 1, *pP1+1);
printf("Index version: %s\n", szTmp);
// version v1 -400 == 60000000h v2 -424 == 66000000h
int nVer = *(BYTE*)(pMem+nMax-32); // var size
if (nVer > 2) nVer = 1;
// print help file name
if (nVer == 1) lstrcpyn(szTmp, (char*)pMem + 1, *pMem+1);
else lstrcpyn(szTmp, (char*)pMem + 2, *(pMem+1)+1);
printf("%s\nVersion: %d\n", szTmp, nVer);
printf("HdrSize: %8X\n", nHdrSize);
printf("HdrOfs:  %8X\n", nHdrOfs);
printf("MaxSize: %8X\n", nMax);

int nCount = 0;
if (nVer == 1) {
nCount = 0x60 / 3;
pP1 = pMem+nMax-396;
} else if (nVer == 2) {
nCount = 0x66 / 3;
pP1 = pMem+nMax-420;
} else return 2;
printf(" offset    count    size     value  bytes\n");
for (int i=0; i<nCount; i++) {
printf("%08X %8X ", pP1-pMem, *(DWORD*)pP1);
pP1 += 4;
printf("%8X ", *(DWORD*)pP1);
int nSize = *(DWORD*)pP1;
pP1 += 4;
printf("%8X|", *(DWORD*)pP1);
if (nSize) {
pP2 = pMem+*(DWORD*)pP1;
//for (int j=0; j<nSize && j<8; j++)
// printf(" %02X", *pP2++);
printf(Mem2HexS(pP2, szTmp, nSize>8?8:nSize));
}
pP1 += 4;
if (nVer == 1) printf("\t%s\n", aName1[i]);
else printf("\t%s\n", aName2[i]);
}
printf("Chksum:  %8X\n", *(DWORD*)(pMem+nMax-12));
printf("Offset:  %8X\n", *(DWORD*)(pMem+nMax-8));
printf("Size:    %8X\n", *(DWORD*)(pMem+nMax-4));

int nCntMax;
// nMax - nOfs => pCnt
nCntMax = *(DWORD*)(pMem+nMax-48); // ?32fileinfo
pP1 = pMem+*(DWORD*)(pMem+nMax-40);
//ShowFileInfo(pMem, pP1, nCntMax, nVer);

nCntMax = *(DWORD*)(pMem+nMax-400-8); // ?2filenames v2
pP1 = pMem+*(DWORD*)(pMem+nMax-400);
//ShowInfo(pMem, pP1, nCntMax, nVer);
nCntMax = *(DWORD*)(pMem+nMax-228); // ?17HelpId
pP1 = pMem+*(DWORD*)(pMem+nMax-220);
//ShowInfo(pMem, pP1, nCntMax, nVer);
nCntMax = *(DWORD*)(pMem+nMax-192); // ?20keywords
pP1 = pMem+*(DWORD*)(pMem+nMax-184);
//ShowInfo(pMem, pP1, nCntMax, nVer);
nCntMax = *(DWORD*)(pMem+nMax-156); // ?23keywords
pP1 = pMem+*(DWORD*)(pMem+nMax-148);
//ShowInfo(pMem, pP1, nCntMax, nVer);
nCntMax = *(DWORD*)(pMem+nMax-84); // ?29HelpId
pP1 = pMem+*(DWORD*)(pMem+nMax-76);
//ShowInfo(pMem, pP1, nCntMax, nVer);
return 0;
}
char *aName1[] = {"?","?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","?27Help.Id","?28","?29","?30"
,"?31","?helpfile"};

char *aName2[] = {"?","?2filenames","?3","?4","?5","?6","?7","?8","?9","?10"
,"?11","?12","?13","?14Category","?15Category","?16"
,"?17HelpId","?18HelpIdIdx","?19","?20keywords"
,"?21kwinfo","?22","?23keywords","?24kwinfo","?25","?26F1","?27F1idx"
,"?28","?29HelpId","?30HelpIdIdx"
,"?31","?32fileinfo","?33","?helpfile"};

char *Mem2HexS(char *pMem, char *pBuf, int nLen)
{
char *p = pMem;
nLen *= 3;
for (int i=0; i<nLen; i+=3) {
unsigned char c = *p;
unsigned char b, cnt;
cnt = 2;
do {
cnt--;
b = c & 0xF;
if (b >= 10)
pBuf[i+cnt] = (char)('A' + (b - 10));
else
pBuf[i+cnt] = (char)('0' + (b));
c = c >> 4;
pBuf[i+2] = ' ';
} while (cnt);
p++;
}
*(pBuf+nLen-1) = 0; // remove last space
return pBuf;
}

void ShowFileInfo(BYTE *pMem, BYTE *pPtr, int nCntMax, int nVer)
{
char szTmp[512];
BYTE *pP1, *pP2;
pP1 = pPtr;
int nCount = 0;
printf("\nOfs\n");
while (nCount<nCntMax) {
printf("%4X ", pP1-pMem);
pP2 = pP1 + 1; // past size
if (*pP2) pP2 += *pP2;
pP2++;
if (!*pP2) break; // error
lstrcpyn(szTmp, (char*)pP2 + 1, *pP2+1);
//printf("%4Xh ", *(WORD*)(pP1+*pP2+2)); // data after string
printf("%s\n", szTmp);
pP1 += *pP1+2; // rec size + ?
nCount++;
}
}

void ShowInfo(BYTE *pMem, BYTE *pPtr, int nCntMax, int nVer)
{
char szTmp[512];
BYTE *pP1, *pP2;
pP1 = pPtr;
int nCount = 0;
printf("\nInfo\n");
while (nCount<nCntMax) {
pP2 = pP1 + 1;
if (!*pP2 || *pP2 > *pP1) break; // error
lstrcpyn(szTmp, (char*)pP2 + 1, *pP2+1);
printf("%4Xh ", *(WORD*)(pP1+*pP2+2)); // data after string
printf("%s\n", szTmp);
pP1 += *pP1 + 1;
nCount++;
}
}
To collect info:
Code: [Select]
@SET INFO=test_hdr.txt
@ECHO mshi info > %INFO%
@FOR %%f IN (*.mshi) DO (
@ECHO. >> %INFO%
@ECHO %%f >> %INFO%
@TestMSHI_hdr.exe "%%f" >> %INFO%
)
Fabrikam_SouthPark_Example.mshc
« Last Edit: September 29, 2018, 12:05:44 PM by TimoVJL »
May the source be with you