1
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
/*
* Windows Help
*
* Copyright 1996 Martin von Loewis
* 2002 Eric Pouech
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include "wine/debug.h"
#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
#include "winnls.h"
WINE_DEFAULT_DEBUG_CHANNEL(win);
/* Wine doesn't use the way WinHelp API sends information in Windows, because:
* 1/ it's not consistent across Win9x, NT...
* 2/ NT implementation is not yet fully understood (and includes some shared
* memory mechanism)
* 3/ uses a dynamically allocated message number (WM_WINHELP), which
* obfuscates the code
*
* So we use (for now) the simple protocol:
* 1/ it's based on copy data
* 2/ we tag the message with a magic number, to make it a bit more robust
* (even if it's not 100% safe)
* 3/ data structure (WINHELP) has the same layout that the one used on Win95.
* This doesn't bring much, except not going to far away from real
* implementation.
*
* This means anyway that native winhelp.exe and winhlp32.exe cannot be
* called/manipulated from WinHelp API.
*/
typedef struct
{
WORD size;
WORD command;
LONG data;
LONG reserved;
WORD ofsFilename;
WORD ofsData;
} WINHELP;
/* magic number for this message:
* aide means help is French ;-)
* SOS means ???
*/
#define WINHELP_MAGIC 0xA1DE505
/**********************************************************************
* WinHelpA (USER32.@)
*/
BOOL WINAPI WinHelpA( HWND hWnd, LPCSTR lpHelpFile, UINT wCommand, ULONG_PTR dwData )
{
COPYDATASTRUCT cds;
HWND hDest;
int size, dsize, nlen;
WINHELP* lpwh;
hDest = FindWindowA("MS_WINHELP", NULL);
if (!hDest)
{
if (wCommand == HELP_QUIT) return TRUE;
if (WinExec("winhlp32.exe -x", SW_SHOWNORMAL) < 32)
{
ERR("can't start winhlp32.exe -x ?\n");
return FALSE;
}
if (!(hDest = FindWindowA("MS_WINHELP", NULL)))
{
FIXME("Did not find a MS_WINHELP Window\n");
return FALSE;
}
}
switch (wCommand)
{
case HELP_CONTEXT:
case HELP_SETCONTENTS:
case HELP_CONTENTS:
case HELP_CONTEXTPOPUP:
case HELP_FORCEFILE:
case HELP_HELPONHELP:
case HELP_FINDER:
case HELP_QUIT:
dsize = 0;
break;
case HELP_KEY:
case HELP_PARTIALKEY:
case HELP_COMMAND:
dsize = dwData ? strlen((LPSTR)dwData) + 1 : 0;
break;
case HELP_MULTIKEY:
dsize = ((LPMULTIKEYHELPA)dwData)->mkSize;
break;
case HELP_SETWINPOS:
dsize = ((LPHELPWININFOA)dwData)->wStructSize;
break;
default:
FIXME("Unknown help command %d\n", wCommand);
return FALSE;
}
if (lpHelpFile)
nlen = strlen(lpHelpFile) + 1;
else
nlen = 0;
size = sizeof(WINHELP) + nlen + dsize;
lpwh = HeapAlloc(GetProcessHeap(), 0, size);
if (!lpwh) return FALSE;
cds.dwData = WINHELP_MAGIC;
cds.cbData = size;
cds.lpData = (void*)lpwh;
lpwh->size = size;
lpwh->command = wCommand;
lpwh->data = dwData;
if (nlen)
{
strcpy(((char*)lpwh) + sizeof(WINHELP), lpHelpFile);
lpwh->ofsFilename = sizeof(WINHELP);
} else
lpwh->ofsFilename = 0;
if (dsize)
{
memcpy(((char*)lpwh) + sizeof(WINHELP) + nlen, (LPSTR)dwData, dsize);
lpwh->ofsData = sizeof(WINHELP) + nlen;
} else
lpwh->ofsData = 0;
TRACE("Sending[%u]: cmd=%u data=%08x fn=%s\n",
lpwh->size, lpwh->command, lpwh->data,
lpwh->ofsFilename ? (LPSTR)lpwh + lpwh->ofsFilename : "");
return SendMessageA(hDest, WM_COPYDATA, (WPARAM)hWnd, (LPARAM)&cds);
}
/**********************************************************************
* WinHelpW (USER32.@)
*/
BOOL WINAPI WinHelpW( HWND hWnd, LPCWSTR helpFile, UINT command, ULONG_PTR dwData )
{
INT len;
LPSTR file;
BOOL ret = FALSE;
if (!helpFile) return WinHelpA( hWnd, NULL, command, dwData );
len = WideCharToMultiByte( CP_ACP, 0, helpFile, -1, NULL, 0, NULL, NULL );
if ((file = HeapAlloc( GetProcessHeap(), 0, len )))
{
WideCharToMultiByte( CP_ACP, 0, helpFile, -1, file, len, NULL, NULL );
ret = WinHelpA( hWnd, file, command, dwData );
HeapFree( GetProcessHeap(), 0, file );
}
return ret;
}