Click here to Skip to main content
15,887,027 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I am using Pelles C and Hunspell to check the spelling of a word in Windows and add new words to Hunspell for the current session. The code for checking the spelling of a word works fine but the code for adding a word to the current session causes my program to crash.

What I have tried:

The section of code relevant to adding a word to the current session is below:

Globals:
C
int Hunspell_add(const char *word);
typedef int (__fastcall *HunspellAddWordFunc)(const char *word);

Function to add a word:
C
int HunspellAddWord(const char *Word2Add){

	int result = -1;
	//Check the hunspell library has been initialised
	if (hHunspellLib == NULL) {
	    MessageBox(0, "Hunspell library not initialized\n\n", 
                   "ERROR", MB_OK | MB_ICONERROR);
	    return result;
	}

if (Word2Add == NULL) {
    MessageBox(0, "Word2Add is invalid for\n\nHunspellAddWord", 
              "ERROR", MB_OK | MB_ICONERROR);
    return result;
	}

	HunspellAddWordFunc Hunspell_add = 
    (HunspellAddWordFunc)GetProcAddress(hHunspellLib, "Hunspell_add");
	if (Hunspell_add == NULL) {
		MessageBox(0, "GetProcAddress failed for\n\nHunspell_add", 
                   "ERROR", MB_OK | MB_ICONERROR);
	    return result;
		}

	if (Hunspell_add != NULL){
		Hunspell_add(Word2Add);
		}
	return -1;
}

Code to test the function to add a word (this is called via a menu):
C
const char *Word2Add = "isospin";
HunspellAddWord(Word2Add);

If I comment out the line "Hunspell_add(Word2Add);", the program does not crash.

How can I update the code to prevent the program from crashing?
Posted
Updated 12-Sep-23 11:30am
v4
Comments
Richard MacCutchan 8-Sep-23 11:51am    
First you need to find out why it crashes. Use the debugger to step through the above method to see what is going on.

[edit]
I have just run a simple test and I think you need to remove the __fastcall specifier in your typedef.
Richard MacCutchan 8-Sep-23 12:09pm    
Interesting name btw, are you a Ted Heath fan?
MorningCloud 8-Sep-23 12:40pm    
I tried removing the __fastcall specifier in my typedef as suggested and I also tried changing it to __stdcall but the program still crashed.

MorningCloud is not associated with Ted Heath. This was a member of a tribe in a book I once read and for some reason I decided to use it as my pseudo name.
Richard MacCutchan 8-Sep-23 12:51pm    
It was also the name of Ted's yacht.
Rick York 8-Sep-23 18:09pm    
What I don't understand is why you have to load the DLL and obtain the function address. You can build a static link library and make that unnecessary. Normally when a DLL is built a .LIB file is generated so, again, you don't have load the DLL at run-time. In other words, if you link to the library correctly you will not have to load it at run-time.

Some things to check:

Are you sure of the signature of the hunspell_add function? If it's expecting a non-const char* it may be trying to modify its argument, or it may require other arguments than you are passing.

Has the value of hHunspellLib changed since the library was initialized? It might not be null but it might have been clobbered in the meantime. Are you sure it's initialized to NULL?

What's the exit code when the program crashes? That might give you some clue as to what the issue is.

How do you know that the crash occurs when calling HunspellAdd()? Do you have stack trace or logs that point to this, or do you just think that's where the issue is.

As Rick MacCutchen noted, the debugger is your friend ...
 
Share this answer
 
v2
Comments
Richard MacCutchan 8-Sep-23 12:21pm    
I wish I had a nice short name like yours, so people would not mis-spell it so much. :(
k5054 8-Sep-23 12:37pm    
My apologies. I'll try to remember next time.
Richard MacCutchan 8-Sep-23 12:49pm    
I was half joking, your spelling was far from the worst I have seen, or heard.
MorningCloud 8-Sep-23 12:42pm    
According to the documentation hunspell3.pdf at Hunspell - Browse /Hunspell/Documentation at SourceForge.net[^] the hunspell_add function expects a non-const char*.

The value of hHunspellLib is set up only once in my program and so its value cannot change (unless the Hunspell DLL is making it change, which is very unlikely).

I don't get an exit code when the program crashes. I know how to do this for a console program but I don't know how to do this for a Windows program.

I know that the crash occurs when calling HunspellAdd() because if I comment out that line in my program it does not crash and another function from the Hunspell DLL, Hunspell_spell, works correctly.
Richard MacCutchan 8-Sep-23 12:50pm    
Is the library available to download anywhere? I would be happy to test this myself.
I have been playing some more with the library and received some mixed results. The following code starts a session with a new dictionary and associated file as described in hunspell(4) - Linux man page[^] (see also hunspell(3) - Linux man page[^] and hunspell(1) - Linux man page[^]). It is difficult to know when the ADD function succeeds, as the results of a spell check are not consistent. I suspect more information is needed but this could be a start. This code was thrown together rather but shows the two basic functions. One important point to note, which I missed yesterday, is the requirement for a HANDLE returned from the Hunspell_create function, which must be past in on all the following calls.
C++
#include <iostream>
#include <string>
#include <windows.h>

using namespace std;


HMODULE hHunspellLib = NULL;
HANDLE hHunspellHandle = NULL;

bool HunspellInit(const char* aff, const char* dic) {

	bool result = false;
	//Check the hunspell library has been initialised
	hHunspellLib = ::LoadLibrary("Hunspellx64");
	if (hHunspellLib == NULL)
	{
		DWORD dw = GetLastError();
		cout << "LoadLibrary failed, error code: " << hex << dw << dec << endl;
	}
	else
	{
		typedef HANDLE (*HunspellCreateFunc)(const char*, const char*);
		HunspellCreateFunc Hunspell_create = (HunspellCreateFunc)GetProcAddress(hHunspellLib, "Hunspell_create");
		if (Hunspell_create == NULL) {
			cout << "GetProcAddress failed for \"Hunspell_create\"" << endl;
		}
		else
		{
			hHunspellHandle = Hunspell_create(aff, dic);
			result = true;
		}
	}

	return result;
}

int HunspellAddWord(const char* Word2Add)
{
	typedef int(*HunspellAddWordFunc)(HANDLE, const char*);
	static HunspellAddWordFunc Hunspell_add = nullptr;

	int result = 0;
	if (Hunspell_add == nullptr)
	{
		Hunspell_add = (HunspellAddWordFunc)GetProcAddress(hHunspellLib, "Hunspell_add");
		if (Hunspell_add == nullptr) {
			cout << "GetProcAddress failed for\n\nHunspell_add" << endl;
			return result;
		}
	}
	else
	{
		result = Hunspell_add(hHunspellHandle, Word2Add);
	}
	return result;
}

int HunspellSpellWord(const char* Word2Spell)
{
	typedef int(*HunspellSpellWordFunc)(HANDLE, const char*);
	static HunspellSpellWordFunc Hunspell_spell = nullptr;

	int result = 0;
	if (Hunspell_spell == nullptr)
	{
		Hunspell_spell = (HunspellSpellWordFunc)GetProcAddress(hHunspellLib, "Hunspell_spell");
		if (Hunspell_spell == nullptr) {
			cout << "GetProcAddress failed for\n\nHunspell_spell" << endl;
			return result;
		}
	}
	else
	{
		result = Hunspell_spell(hHunspellHandle, Word2Spell);
	}
	return result;
}

int main()
{
	if (!HunspellInit("spelltest.aff", "spelltest.dic"))
	{
		return 1;
	}

	string input;
	while (true)
	{
		cout << "enter a word: ";
		cin >> input;
		if (input == "END")
			break;
		if (input == "ADD")
		{
			cout << "enter the word to add: ";
			cin >> input;
			int addresult = HunspellAddWord(input.c_str());
			cout << "add returned: " << addresult << endl;
		}
		else
		{
			int gorb = HunspellSpellWord(input.c_str());
			cout << (gorb == 1 ? "Correct" : "Wrong") << endl;
		}
	}

	return 0;
}

1. Affix file
SET UTF-8
TRY esianrtolcdugmphbyfvkwzESIANRTOLCDUGMPHBYFVKWZ'

REP 2
REP f ph
REP ph f

Dictionary file
5
mouse
handle
door
*pickle
tribulation
 
Share this answer
 
Comments
MorningCloud 10-Sep-23 11:29am    
Thanks, Richard. I am still trying to get this to work but everything I try causes a crash and I can't see why.

I was reluctant to post the full code for my Hunspell program as it is quite large (264 lines) and so I only posted the section that was not working. However, you made me realise that it may help to resolve the problem if I post the full code that includes the part that works (ie check the spelling of a word), so I have made it available in a zip file that can be downloaded from the following link:

https://mega.nz/file/HAsiSKqb#J_wIe_xlnisNj2MXptJ1JzjlIvrWqDx6n7vc_JKrbZU

I have not been able to find out what the return value from Hunspell_add() should be. I can only assume that this is TRUE or FALSE.
Richard MacCutchan 10-Sep-23 12:10pm    
The key thing I discovered was that you need to get a handle from the Hunspell_create function, and pass that to every other function call. The crashes I was getting yesterday were directly attributable to that. I'll take a look at your code next week if i have time.
Richard MacCutchan 11-Sep-23 3:22am    
The cause of the crash is at line 261 of the MainWindow.c file:
	if (Hunspell_add != NULL){
		Hunspell_add(Word2Add); <-- 261, but the handle pointer is missing
		}

It requires the handle pointer dic thus:
			Hunspell_add(dic, Word2Add); // pass also the GLobal pointer
MorningCloud 11-Sep-23 5:19am    
Thanks Richard. However, when I change my code to:
	if (Hunspell_add != NULL){
		Hunspell_add(dic, Word2Add);
		}


I get the error message "Type error in argument 1 to 'function'; expected 'const char *' but found 'Hunhandle (aka (incomplete) struct Hunhandle) *"

The pdf file "hunspell3.pdf" at https://sourceforge.net/projects/hunspell/files/Hunspell/Documentation/ seems to indicate that when programming in the C language the handle is not needed. It looks as thought there is quite a difference between programming in C++ and in C.
Richard MacCutchan 11-Sep-23 6:03am    
Sorry, I forgot that you also need to change the declarations at the beginning:
int Hunspell_add(Hunhandle *pHunspell, const char *word);  //Declare the function type
typedef int (__stdcall *HunspellAddWordFunc)(Hunhandle *pHunspell, const char *word); 	//Declare a type for the function pointer

The handle is always needed when coding in C. However, in C++ the handle is held inside the class object. That is why the pdf document does not show it; all those calls are available in C++ only.
Your code calling the function is not correct. It should be like this :
C
if( hunspell_add )
{
    (*hunspell_add)( word2Add );
}
You have to dereference the pointer.


This is wrong so never mind.
 
Share this answer
 
v2
Comments
k5054 8-Sep-23 11:57am    
No, you do not: cf https://www.geeksforgeeks.org/function-pointer-in-c/
Richard MacCutchan 8-Sep-23 12:04pm    
That is not correct, the dereferencing happens automatically with function pointers.
There are some confusing parts to this. According to DUMPBIN Reference | Microsoft Learn[^] , the only method that includes the name add_word is ?add_word@HashMgr@@AEAAHPEBDHHPEAGH0_N@Z. Using undname (Decorated names | Microsoft Learn[^]) this decodes to:
C:\Users\rjmac\source\repos\kandrTest\spelltest\Debug>undname ?add_word@HashMgr@@AEAAHPEBDHHPEAGH0_N@Z
Microsoft (R) C++ Name Undecorator
Copyright (C) Microsoft Corporation. All rights reserved.

Undecoration of :- "?add_word@HashMgr@@AEAAHPEBDHHPEAGH0_N@Z"
is :- "private: int __cdecl HashMgr::add_word(char const * __ptr64,int,int,unsigned short * __ptr64,int,char const * __ptr64,bool) __ptr64"

Ignore the above, I was .ooking at the wrong method name.

Using the same call as shown in the original question the code works fine - as far as I can tell. The only stipulation that I can see is that the code must be compiled to 64-bit, even though it uses char types, rather than wchar_t.

[edit]
This is the code i have been using which appears to work:
C++
typedef int(__fastcall* HunspellAddWordFunc)(const char* word);


int HunspellAddWord(const char* Word2Add) {

	int result = -1;
	//Check the hunspell library has been initialised
	HMODULE hHunspellLib = ::LoadLibraryW(L"Hunspellx64");

	if (hHunspellLib == NULL) {
		DWORD dw = GetLastError();
		cout << "Hunspell library not initialized" << endl;
		return result;
	}

	if (Word2Add == NULL) {
		cout << "Word2Add is invalid for\n\nHunspellAddWord" << endl;
		return result;
	}

	HunspellAddWordFunc Hunspell_add = (HunspellAddWordFunc)GetProcAddress(hHunspellLib, "Hunspell_add");
	if (Hunspell_add == NULL) {
		cout << "GetProcAddress failed for\n\nHunspell_add" << endl;
		return result;
	}

	if (Hunspell_add != NULL) {
		result = Hunspell_add(Word2Add);
		cout << "result: " << result << endl;
	}
	return result;
}

I say "appears", as I do not know how to check it is correct. The return value from the add is always zero, and any word longer than 8 characters crashes the application. You may need to consult the library documentation.

[/edit]
 
Share this answer
 
v3
Comments
MorningCloud 9-Sep-23 9:16am    
That's strange. I am compiling the program in Windows 11 as a 64-bit exe file using Pelles C. I used the debugger and this reported "Exception: Access violation" although I have no idea why this is happening.
Richard MacCutchan 9-Sep-23 9:24am    
I use Microsoft's compiler and the compiled code works to an extent - see my update above.
MorningCloud 9-Sep-23 10:09am    
Strange that it crashes for words larger than 8 characters. I can't see any differences between the code you used and the code I used except you used LoadLibraryW(L"Hunspellx64"); whereas I used LoadLibrary("Hunspellx64.dll");

Unfortunately the documentation is very sparse. This states:
"int add(const char *word);"
...
"The add(), add_with_affix() and remove() are helper functions of a personal dictionary implementation to add and remove words from the base dictionary in run-time."

I find that it crashes on my PC with three lettered words.
Richard MacCutchan 9-Sep-23 10:16am    
There is no difference between LoadLibrary("Hunspellx64.dll"); and LoadLibraryW(L"Hunspellx64.dll");, in that the same library will be loaded into the application's address space. Sorry, but without detailed documentation on these functions it is impossible to make any further suggestions.
MorningCloud 9-Sep-23 13:23pm    
Thanks for looking into this. It's very irritating that the documentation is so poor. I spent a lot of time looking in the internet for further information about Hunspell. Although it seems to be widely used there is virtually no information or examples for using it in the C language.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900