Re: FLI problem, maybe because of nested structs
Hi Martin,
Thanks a lot for your quick replies. That gives me something to think
about and try and I'll report back to the list.
About the alignment problem, I thought I had looked for a "pack"
pragma in the header file, but I now checked again and it turns out I
hadn't or I overlooked it. D'oh!!!
And, yes, I first had :stdcall in there but changed it because I
thought that might have been the problem. I rarely look at C code and
usually only if I need to interface to it from Lisp. I'm sure someone
more familiar with it and with the standard compilers would have seen
the problem immediately.
Thanks again,
Edi.
On Wed, Aug 11, 2010 at 2:16 PM, Martin Simmons <martin@lispworks.com> wrote:
>>>>>> On Wed, 11 Aug 2010 13:08:11 +0200, Edi Weitz said:
>>
>> Hi everybody,
>>
>> I'm trying to interface to some C code and I'm having problems with
>> one particular function call. I usually get "Exception C0000005"
>> which I seem to remember means that some pointer or address is
>> mis-interpreted. One argument to the function is a struct within a
>> struct and I /think/ that this must be the culprit, but I can't figure
>> out where exactly the problem is. Here's what I've done (on Windows
>> XP with LWW 5.1):
>>
>> The relevant simple C type definitions are these
>>
>> typedef unsigned short TW_UINT16;
>> typedef unsigned long TW_UINT32;
>> typedef LPVOID TW_MEMREF;
>> typedef char TW_STR32[34];
>>
>> which I've translated like this:
>>
>> (define-c-typedef dword :unsigned-long)
>> (define-c-typedef handle dword)
>> (define-c-typedef tw-str32 (:ef-mb-string :limit 34 :null-terminated-p t))
>>
>> (The TW_MEMREF argument is, in this particular case, used to hand over
>> a window handle, so in my code below I don't user :POINTER but rather
>> HANDLE.)
>>
>> Now the two structs:
>>
>> typedef struct {
>> TW_UINT16 MajorNum;
>> TW_UINT16 MinorNum;
>> TW_UINT16 Language;
>> TW_UINT16 Country;
>> TW_STR32 Info;
>> } TW_VERSION;
>>
>> typedef struct {
>> TW_UINT32 Id;
>> TW_VERSION Version;
>> TW_UINT16 ProtocolMajor;
>> TW_UINT16 ProtocolMinor;
>> TW_UINT32 SupportedGroups;
>> TW_STR32 Manufacturer;
>> TW_STR32 ProductFamily;
>> TW_STR32 ProductName;
>> } TW_IDENTITY, FAR * pTW_IDENTITY;
>>
>> And here's my Lisp version of them:
>>
>> (define-c-struct tw-version
>> (major-num :unsigned-short)
>> (minor-num :unsigned-short)
>> (language :unsigned-short)
>> (country :unsigned-short)
>> (info tw-str32))
>>
>> (define-c-struct tw-identity
>> (id :unsigned-long)
>> (version tw-version)
>> (protocol-major :unsigned-short)
>> (protocol-minor :unsigned-short)
>> (supported-groups :unsigned-long)
>> (manufacturer tw-str32)
>> (product-family tw-str32)
>> (product-name tw-str32))
>>
>> Does this look right?
>
> Yes, but it would be easier to check if you use define-c-typedef to define
> TW_UINT16 and TW_UINT32 and then use those wherever C does.
>
>
>> Could there be a problem with alignment that
>> I'm missing? FWIW, the header file is supposed to be understood by
>> various compilers including Microsoft's.
>
> Yes, that could be the problem. I found
> http://twainmodule.sourceforge.net/docs/lowlevel.html which says:
>
> "Note: The TWAIN standard pack values to two byte boundaries. In normal C
> structures there is a padding of two bytes before SupportedGroups. However, in
> the TWAIN interface there is none."
>
> Does the header file mention "pack" anywhere (e.g. #pragma pack)?
>
> If the whole file uses 2 byte packing then you need to add (:byte-packing 2)
> before the slots in all of the structs.
>
>
>> Here, finally is the function:
>>
>> TW_UINT16 FAR PASCAL DSM_Entry( pTW_IDENTITY pOrigin,
>> pTW_IDENTITY pDest,
>> TW_UINT32 DG,
>> TW_UINT16 DAT,
>> TW_UINT16 MSG,
>> TW_MEMREF pData);
>>
>> I've searched a bit and my understanding is that both FAR and PASCAL
>> are compatibility decorations which are needed for 16-bit Windows but
>> are ignored on 32-bit platforms.
>>
>> Here's the Lisp definition:
>>
>> (define-foreign-function (dsm-entry "DSM_Entry")
>> ((p-origin :pointer)
>> (p-dest :pointer)
>> (dg :unsigned-long)
>> (dat :unsigned-short)
>> (msg :unsigned-short)
>> (p-data handle))
>> :calling-convention :cdecl
>> :result-type :unsigned-short)
>>
>> Does anyone spot anything that I could have done wrong?
>
> PASCAL expands to __stdcall in VC++, so I think it should be
> :calling-convention :stdcall.
>
> --
> Martin Simmons
> LispWorks Ltd
> http://www.lispworks.com/
>
>