I'm playing around a bit with the virtual file system API.
When I pass my ContextMenuData structure to DOPus it throws an Access Violation (0xC0000005). I feel like I'm missing something obvious here, perhaps someone can take a look at my code.
The exported function looks like this
function VFS_GetContextMenuA(hVFSData: THandle; lpFuncData: PVFSFuncData; lpszFiles: LPTSTR; var lpMenuData: TVFSContextMenuDataA): Boolean; cdecl;
lpMenuData.fAllowContextMenu := True;
lpMenuData.fDefaultContextMenu := False;
lpMenuData.fCustomItemsBelow := False;
lpMenuData.lpCustomItems := Instance(hVFSData).GetContextMenu();
lpMenuData.iNumCustomItems := 1;
lpMenuData.fFreeCustomItems := False;
Result := True;
The GetContextMenu method looks like this: (FContext is a field of the TVFSWrapper object of type PVFSContextMenuItemA and is initially nil)
function TVFSWrapper.GetContextMenu: PVFSContextMenuItemA;
CM_LABEL = 'label';
CM_COMMAND = 'Go OPENINDUAL';
if FContext = nil then
THandle(FContext) := LocalAlloc(LPTR, SizeOf(TVFSContextMenuItemA));
FContext^.cbSize := SizeOf(TVFSContextMenuItemA);
FContext^.dwFlags := 0;
THandle(FContext^.lpszLabel) := LocalAlloc(LPTR, length(CM_LABEL) + 1);
THandle(FContext^.lpszCommand) := LocalAlloc(LPTR, length(CM_COMMAND) + 1);
Result := FContext;
For completeness, here is my definition of the ContextMenuItemA and ContextMenuDataA structures:
PVFSContextMenuItemA = ^TVFSContextMenuItemA;
TVFSContextMenuItemA = record
cbSize : UINT;
dwFlags : DWORD;
lpszLabel : LPSTR;
PVFSContextMenuDataA = ^TVFSContextMenuDataA;
TVFSContextMenuDataA = record
cbSize : UINT;
fAllowContextMenu : BOOL;
fCustomItemsBelow : BOOL;
lpCustomItems : PVFSContextMenuItemA;
iNumCustomItems : integer;
fFreeCustomItems : BOOL;
When I set iNumCustomItems to 0, all works fine. So I expect that I'm making a mistake in allocating the memory for the ContextMenuItem in the GetContextMenu function.
Any ideas on this? Thanks in advance.
I can't see anything that is obviously wrong, although my knowledge of Pascal is limited so maybe I'm assuming something is doing the right thing when it really does something else.
Maybe the quickest way to find out what's causing the crash would be to post a compiled version of the DLL. This could then be called from C++ (either via Opus itself or a small test harness) under a debugger to see what the structure looks like on the C++ side.
BTW, it might save you some time/hassle to make it use Unicode instead of ANSI strings. Converting stuff after it has been written is tedious but writing for Unicode from the start is no extra work, unless it doesn't make sense for another reason.
If you post a compiled DLL I can run it in Opus under the debugger and see where it's crashing. I don't know anything about Pascal but it all LOOKS ok - is it possible there are structure alignment differences between Pascal and C++ ?
Jon, that is what I expected as well. On the other hand, several other structures such as e.g. the ReadDirData and the ContextMenuData (without any custom entries) work fine.
I know there are problems with passing native Delphi strings to C/C++ programs due to difference in memory allocation, however when using pchars this should not be an issue (and it isn't in e.g. ReadDirectory).
This is a very bare version of the plugin, which I was using to troubleshoot this problem myself. It handles the prefix: 'nntp://' and lists a couple of test directories.
Thanks for the offer to test guys.
DelphiPluginTest.zip (195 KB)
CM_LABEL and CM_COMMAND are pascal strings, lpszLabel and lpszCommand are C string pointers, I think you should use StrPCopy instead of StrCopy.
Hmmm. That might indeed be a bit safer, but it doesn't make a difference.
I already did a test to see if those strings were null terminated and they were, but that might be because LocalAlloc with argument LPTR zeroes the allocated memory.
Sorry for the trouble, it's an Opus bug
Specifically, it's an error in the ANSI->Unicode conversion wrapper. If you implement VFS_GetContextMenu as a unicode function it should work fine.
We will fix this in the next version!
Ah, that's good to know. Thanks for checking jon.