Inside Wine; How to install MSDN Library October 2001 (English version)

[TOC] (https://qiita.com/Yutaka_Aoki/items/9d38ea98406f4096435b)

# Inside Wine; How to install MSDN Library October 2001 (English version)

Let me conclude first.

1. If you do the following way, you can successfully complete "Full Install" of three CDs, and the basic functions of HTML HELP of MSDN Library can be used.
2. For example, you can display the contents, table of contents, use an index search (and incremental search), full text search, a synchronization to table of contents, and define and create of your original search subsets.
3. The problems which were found :
  1. Select an index tab in the left pane, enter the index word into an edit box, and select an item the list below. But if there are some further multiple candidates, the dialog box which have the candidate list will appear as a popup window. If you select a line in the candidate list, whichever is selected, only the first line candidate will be always displayed in the right pane, and the second line or below candidates can not be displayed at all.
  2. The default font is too small and all the maximum, large, medium, small and smallest items in the "display-font" menu are disabled and gray colored. But this has been known well. And you can fix the problem by uncompressing the CHM file, reverting to HTML, modifying css and style, and rebuilding CHM.
4. As a countermeasure against "3.1", you can partly fix the problem to some extent by defining a subset and excluding unnecessary chapters or sections from searching. But still, for example, if you enter SetFocus in the edit box, and select the item list in the left pane below the edit box, and select the second item or more below in the list in the popup dialog which have candidate list which consists of COleControl::SetFocus, CWnd::SetFocus, CWindow::SetFocus, ::SetFocus, etc, you can display the only item for COleControl::SetFocus(), whichever item you selected in the dialog box. Therefore, it is difficult to display simple ::SetFocus() Win32 API from an index search.


## Emergency reports, 2018/03/04

If you leave it untouched as the way which is explained in the following, some link elements in those html help which are not normal html A tag links but special links which use MS java script can't be jumped to.

But if you copy relevant *.ocx and *.dll from original windows system32 folder to .wine system32 folder and use the just following script, that problem disappear.


```bash:
#!/bin/bash

WINEDLLOVERRIDES='hhctrl.ocx=n'
WINEDLLOVERRIDES+=';comctl32=n'
WINEDLLOVERRIDES+=';mshtml=n'
WINEDLLOVERRIDES+=';shlwapi=n'
WINEDLLOVERRIDES+=';wininet=n'
WINEDLLOVERRIDES+=';urlmon=n'
WINEDLLOVERRIDES+=';itss=n'
WINEDLLOVERRIDES+=';shdocvw=n'

export WINEDLLOVERRIDES

wine /media/Xxxx/WINDOWS/hh.exe e:/MSDN/2001OCT/1033/MSDN130.COL
```


## Emergency reports, 2018/03/03

I found in 2018/03/03 that if you copy comctl32.dll from MS Original Windows/system32 to .wine system32 folder, and set to use that native dll for comctl32.dll and run hh.exe, the 3.1 problem above will disappear. Then you will be able to display ::SetFocus() Win32 API from the index search directly.


--------------------------

In the following, the case of "Full Install" will be explained.

# Preparing to mount an optical drive

Write mounting information for optical drives (BD, DVD, CD, etc) in /etc/fstab. This is not necessary, but for making a command line easier, I wrote it.

However, as a side effect of this, Ubuntu will not be able to mount on the drive at the time of startup and will be in a long standby state, so you will have to press the "s" key for skipping to mount the optical drive. So it is maybe better that you write a script or use bash alias.


Make sure you already have a folder /mnt/dvd. If you have not yet, do

```
$ sudo mkdir /mnt/dvd
```

Next,


```
$ sudo gedit /etc/fstab
```

In the /etc/fstab, add the end line of the following :

```
# <file system> <mount point> <type> <options> <dump> <pass>

# omitted

/dev/sr0 /mnt/dvd iso9660  ro,user,auto   0   0
```


## Installation procedure

### 1. Insert CD-ROM into optical drive

Insert the MSDN Library CD-ROM into the optical drive.

### 2. Mount to Optical Drive

```
$ sudo mount /mnt/dvd
```

### 3. Assign the drive letter F: to the optical drive.

```
$ winecfg
```

For example, assign /mnt/dvd to the "F:" drive of Windows (in wine).

### 4. Change the current directory


```
$ cd /mnt/dvd
```

### 5. Start the MSDN Libray installer

```
$ wine setup.exe
```

As the installer starts up, answer a few questions and specify the installation destination folder. Below, it is assumed that the installation destination folder is "e:/MSDN".


If you press the "Full Install" button, copying of the files from the CD-1 to the installation destination folder will start.


### 6. A font-related error dialog appears (Japanese). 

It seems that Wine's emulator prints out that messages and the installer itself does not concern that messages.

If you press "ignore" (or so) button, it will continue the installation without terminating the installation.


### 7. Media exchange to CD-2

When a dialog prompting media exchange appears, do as follows. If you do not do it this way, you may not go well.

First, start a new terminal. In the case of Ubuntu, right-click the terminal icon on the vertical taskbar on the left side of the desktop and select "New terminal".

In that new terminal, enter

```
$ wine eject f:
```

Then, the tray of the optical drive will be ejected and the CD-1 media comes out. And replace the media with CD-2, press the tray with your fingers, and put the media in the drive.

Enter again :

```
$ sudo mount /mnt/dvd
```

After that, press the "Continue" (or so) button on the installer's "Please insert CD-2" (or so) dialog.


### 8. Repeat the same for CD-3.



### 9. Installation finishes.


Icons are also created on the desktop. The real problem is around start-up of the hh command.


# Check the present circumstance

Here, enter the command line as the following :

```
$ wine hh e:/MSDN/2001OCT/1033/MSDN130.COL
```

Then, the following message will appear in the terminal and it can not to be started :

01bd:err:htmlhelp:doWinMain Failed to open HTML Help file 'e:/MSDN/2001OCT/1033/MSDN130.COL'.




But the following way will fix the problem.


## How to run the HTML HELP from the command line

You can run the HTML HELP from the command line as follows.

At first,

```
$ cd ~/.wine/dirve_c/windows/system32
```

Copy the following file in "?:/Windows/system32" of the original Windows to the current directoy :

```c:?/windows/system32
hhctrl.ocx
```

The current directory is (~/.wine/dirve_c/windows/system32). This can be done from the Nautilus or a cp command.

After copying, Read :

Link: [Use original (native) regsvr32] (https://qiita.com/Yutaka_Aoki/items/9655d714519797967c2e)

If you use a (built-in) regsvr32.exe which is distributed as the part of a default Wine binary, you will fail. Because the version does not write a UUID correspond to hhctrl.ocx in the registry at all. So you need to use a native version regsver32.exe of an original Window.

The only thing which you need to do is to copy ulib.dll and clb.dll from `c:/windows/system32` to system32 folder of `~/.wine` .

Fortunatlely(?), ulib.dll and clb.dll does not exist in the default Wine binary distribution. you can copy safely without concerning overwriting the files.



Here, use regsvr32.exe in an original Windows :

```
wine /media/XXXXX/WINDOWS/system32/regsvr32.exe hhctrl.ocx
```

In the /media/XXXXX part, change and write the path name in Linux correspond to the original Windows OS drive.

This will register hhctrl.ocx to Windows COM SERVER (on Wine), and write the UUID correspond to hhctrl.ocx in the registry in Wine Emulator.


Next,

```
$ export WINEDLLOVERRIDES=hhctrl.ocx=n
```

Set the environment variable WINEDLLOVERRIDES to specify to use the Windows native version of hhctrl.ocx rather than Wine built-in version.

After that,

```
$ wine hh e:/MSDN/2001OCT/1033/MSDN130.COL
```

Then, MSDN Library Otober 2001 (English version) will be launched as you can see.


## How to run the HTML HELP from desktop icon

Right click on the desktop icon and look at the property, the command column is as follows:

`env WINEPREFIX="/home/taro-yamada/.wine" wine C:\\windows\\hh.exe e:\\MSDN\\2001OCT\\1033\\MSDN130.COL`

(Taro yamada is a typical or common name in Japan.)

As "taro-yamada" is a login name (?), your current login name (?) appears.


Change this column as follows:

`env WINEPREFIX="/home/taro-yamada/.wine" WINEDLLOVERRIDES=hhctrl.ocx=n wine C:\\windows\\hh.exe e:\\MSDN\\2001OCT\\1033\\MSDN130.COL`


Now, if you click on the icon, it will run.



## Reference: UUID of hhctrl.ocx


Link: (http://www.nongnu.org/chmspec/latest/Miscellaneous.html#GUIDs_HHCtrl_SystemSort)


```
6.1.4. {4662DAB0-D393-11D0-9A56-00C04FB68B66}

From: $OBJINST internal file.
InprocServer32: HHCTRL.OCX
ThreadingModel: Both
VersionIndependentProgID: HHCtrl.SystemSort
ProgID: HHCtrl.SystemSort.666
```



# About the reason why you can't display the items below the second candidates in a tab of index search

## Survey by using MS Spy++


First, run and display HTML HELP of MSDN Library, then,

In the directory 

`c:/Program Files/Microsoft Visual Studio/Common Tools`

Enter

```
$ wine spyxx
```

Then you can run Spy++ to survey the window information.


In the left pane in HTML HELP :

At the edit box which says "Enter index words" in an index tab, enter a some keyword and press an enter key.

A dialog box titled "Applicable topic" which shows "Click on the topic, then click(T)" at the top of the contents will appear. And the header of the list box is "title" and "place". And a list box have the lines :

```
COleDontrol::SetFocus  Microsoft Foundation Class Library and Templates
CWindow::SetFocus      Microsoft Foundation Class Library and Templates
CWnd::SetFocus         Microsoft Foundation Class Library and Templates
SetFocus               Windows User Interface: Platform SDK
SetFocus Method        Visual Stdio Environment
```

And "Display (D)" and "Cancel" buttons are on the rightmost end at the bottom.


In Spy++, you can see :

```
-X 000F005C "Applicable topic" #32770 (dialog)
 -X 000D01A6 "List1" SysListView32
    X 000C01A0 "" SysHeader32
   X 00130138 "Display(&D)" Button
   X 000F00CC "Cancel" Button
   X 0002022A "Click the topic, then click 'Display' (&T)" Static
```

So you can confirm that the program code to show this list is the window of "SysListView32" (WC_LISTVIEW) class of Win32 that is correspond to CListCtrl in MFC.

```c:
source:    ~/wine/dlls/comctl32/listview.c
classname: WC_LISTVIEW : "SysListView32"
func:      LISTVIEW_WindowProc
```

Here, if you select the fourth line in the list above as :

```
SetFocus               Windows User Interface: Platform SDK
```

From the view of a program code, one of the ways to get the index of the selected items is to use the following functions in MFC. But there are various other ways, for example, notification messages to a parent window or callback function for custom draw.


```c:
int CListCtrl::GetNextItem(int nItem, int nFlags) const
	{ ASSERT(::IsWindow(m_hWnd)); return (int) ::SendMessage(m_hWnd, LVM_GETNEXTITEM, nItem, MAKELPARAM(nFlags, 0)); }

POSITION CListCtrl::GetFirstSelectedItemPosition() const
	{ ASSERT(::IsWindow(m_hWnd)); return (POSITION) (1+GetNextItem(-1, LVIS_SELECTED)); }

int CListCtrl::GetNextSelectedItem(POSITION& pos) const
	{ ASSERT(::IsWindow(m_hWnd)); int nOldPos = (int)pos-1; pos = (POSITION) (1+GetNextItem(nOldPos, LVIS_SELECTED)); return nOldPos; }
```

As you can see the above, these MFC function use LVM_GETNEXTITEM message to WC_LISTVIEW Class by calling SendMessage() function.

About POSITION pos,

1. If returned pos from function is "0" as an incorrect value, then you can explain this anomaly.
2. Even if "3" is returned correctly, if the number "3" changes "0" due to some problems in subsequent processing, this problem can be explained, too.



In LISTVIEW_GetNextItem function, if nItem is (-1), then nItem++, and nItem = 0. Then ... ?

I propose to write fprintf( stderr, "xxx" ) code or TRACE() or FIXME() in the LISTVIEW_GetNextItem() function in the state of 'hh.exe' is running.


```c:~/wine/dlls/comctl32/listview.c
static INT LISTVIEW_GetNextItem(const LISTVIEW_INFO *infoPtr, INT nItem, UINT uFlags)
{
    UINT uMask = 0;
    LVFINDINFOW lvFindInfo;
    INT nCountPerColumn;
    INT nCountPerRow;
    INT i;

    TRACE("nItem=%d, uFlags=%x, nItemCount=%d\n", nItem, uFlags, infoPtr->nItemCount);
    if (nItem < -1 || nItem >= infoPtr->nItemCount) return -1;

    ZeroMemory(&lvFindInfo, sizeof(lvFindInfo));

    if (uFlags & LVNI_CUT)
      uMask |= LVIS_CUT;

    if (uFlags & LVNI_DROPHILITED)
      uMask |= LVIS_DROPHILITED;

    if (uFlags & LVNI_FOCUSED)
      uMask |= LVIS_FOCUSED;

    if (uFlags & LVNI_SELECTED)
      uMask |= LVIS_SELECTED;

    /* if we're asked for the focused item, that's only one, 
     * so it's worth optimizing */
    if (uFlags & LVNI_FOCUSED)
    {
	if ((LISTVIEW_GetItemState(infoPtr, infoPtr->nFocusedItem, uMask) & uMask) != uMask) return -1;
	return (infoPtr->nFocusedItem == nItem) ? -1 : infoPtr->nFocusedItem;
    }
    
    if (uFlags & LVNI_ABOVE)
    {
      if ((infoPtr->uView == LV_VIEW_LIST) || (infoPtr->uView == LV_VIEW_DETAILS))
      {
        while (nItem >= 0)
        {
          nItem--;
          if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask)
            return nItem;
        }
      }
      else
      {
        /* Special case for autoarrange - move 'til the top of a list */
        if (is_autoarrange(infoPtr))
        {
          nCountPerRow = LISTVIEW_GetCountPerRow(infoPtr);
          while (nItem - nCountPerRow >= 0)
          {
            nItem -= nCountPerRow;
            if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask)
              return nItem;
          }
          return -1;
        }
        lvFindInfo.flags = LVFI_NEARESTXY;
        lvFindInfo.vkDirection = VK_UP;
        LISTVIEW_GetItemPosition(infoPtr, nItem, &lvFindInfo.pt);
        while ((nItem = LISTVIEW_FindItemW(infoPtr, nItem, &lvFindInfo)) != -1)
        {
          if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask)
            return nItem;
        }
      }
    }
    else if (uFlags & LVNI_BELOW)
    {
      if ((infoPtr->uView == LV_VIEW_LIST) || (infoPtr->uView == LV_VIEW_DETAILS))
      {
        while (nItem < infoPtr->nItemCount)
        {
          nItem++;
          if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask)
            return nItem;
        }
      }
      else
      {
        /* Special case for autoarrange - move 'til the bottom of a list */
        if (is_autoarrange(infoPtr))
        {
          nCountPerRow = LISTVIEW_GetCountPerRow(infoPtr);
          while (nItem + nCountPerRow < infoPtr->nItemCount )
          {
            nItem += nCountPerRow;
            if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask)
              return nItem;
          }
          return -1;
        }
        lvFindInfo.flags = LVFI_NEARESTXY;
        lvFindInfo.vkDirection = VK_DOWN;
        LISTVIEW_GetItemPosition(infoPtr, nItem, &lvFindInfo.pt);
        while ((nItem = LISTVIEW_FindItemW(infoPtr, nItem, &lvFindInfo)) != -1)
        {
          if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask)
            return nItem;
        }
      }
    }
    else if (uFlags & LVNI_TOLEFT)
    {
      if (infoPtr->uView == LV_VIEW_LIST)
      {
        nCountPerColumn = LISTVIEW_GetCountPerColumn(infoPtr);
        while (nItem - nCountPerColumn >= 0)
        {
          nItem -= nCountPerColumn;
          if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask)
            return nItem;
        }
      }
      else if ((infoPtr->uView == LV_VIEW_SMALLICON) || (infoPtr->uView == LV_VIEW_ICON))
      {
        /* Special case for autoarrange - move 'til the beginning of a row */
        if (is_autoarrange(infoPtr))
        {
          nCountPerRow = LISTVIEW_GetCountPerRow(infoPtr);
          while (nItem % nCountPerRow > 0)
          {
            nItem --;
            if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask)
              return nItem;
          }
          return -1;
        }
        lvFindInfo.flags = LVFI_NEARESTXY;
        lvFindInfo.vkDirection = VK_LEFT;
        LISTVIEW_GetItemPosition(infoPtr, nItem, &lvFindInfo.pt);
        while ((nItem = LISTVIEW_FindItemW(infoPtr, nItem, &lvFindInfo)) != -1)
        {
          if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask)
            return nItem;
        }
      }
    }
    else if (uFlags & LVNI_TORIGHT)
    {
      if (infoPtr->uView == LV_VIEW_LIST)
      {
        nCountPerColumn = LISTVIEW_GetCountPerColumn(infoPtr);
        while (nItem + nCountPerColumn < infoPtr->nItemCount)
        {
          nItem += nCountPerColumn;
          if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask)
            return nItem;
        }
      }
      else if ((infoPtr->uView == LV_VIEW_SMALLICON) || (infoPtr->uView == LV_VIEW_ICON))
      {
        /* Special case for autoarrange - move 'til the end of a row */
        if (is_autoarrange(infoPtr))
        {
          nCountPerRow = LISTVIEW_GetCountPerRow(infoPtr);
          while (nItem % nCountPerRow < nCountPerRow - 1 )
          {
            nItem ++;
            if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask)
              return nItem;
          }
          return -1;
        }
        lvFindInfo.flags = LVFI_NEARESTXY;
        lvFindInfo.vkDirection = VK_RIGHT;
        LISTVIEW_GetItemPosition(infoPtr, nItem, &lvFindInfo.pt);
        while ((nItem = LISTVIEW_FindItemW(infoPtr, nItem, &lvFindInfo)) != -1)
        {
          if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask)
            return nItem;
        }
      }
    }
    else
    {
      nItem++;

      /* search by index */
      for (i = nItem; i < infoPtr->nItemCount; i++)
      {
        if ((LISTVIEW_GetItemState(infoPtr, i, uMask) & uMask) == uMask)
          return i;
      }
    }

    return -1;
}

static UINT LISTVIEW_GetItemState(const LISTVIEW_INFO *infoPtr, INT nItem, UINT uMask)
{
    LVITEMW lvItem;

    if (nItem < 0 || nItem >= infoPtr->nItemCount) return 0;

    lvItem.iItem = nItem;
    lvItem.iSubItem = 0;
    lvItem.mask = LVIF_STATE;
    lvItem.stateMask = uMask;
    if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) return 0;

    return lvItem.state & uMask;
}
```














#aaa

bbb

#aaa

bbb

#aaa

bbb

#aaa

bbb

#aaa

bbb

#aaa

bbb

#aaa

bbb

#aaa

bbb

#aaa

bbb

#aaa

bbb

#aaa

bbb

#aaa

bbb

#aaa

bbb