Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2009-12

Problem compiling DLL for 64Bit Windows - complete example attached

7 messages · 4 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Lukas Gradl

Hi!

I'm having serious troubles compiling a DLL for 64bit Windows. I'm using FPC svn 14444 (Ver 2.5.1) on all machines. I tried on WinXP 32bit (works), Vista 64bit (doesn't work), Win7 32Bit (works) and Win7 64bit (doesn't work).

The DLL works as a print-monitor, providing a virtual printer port.

For the definitions I used the windows-Unit whereever it would work, the missing ones (mainly the Monitor-Structure i ported from MSDN. (http://msdn.microsoft.com/en-us/library/aa506794.aspx)

To see the problem copy the resulting dll in your \windows\system32 folder. Then add a registry folder
HKLM\SYSTEM\CurrentControlSet\Control\Print\Monitors\PMon64Test Inside this folder add a string named "Driver" with a value of "PMon64.dll" (which has to be the name of the dll in the System32 Folder. Restart the Spooler-Service and try to add a Printer to your system.

On Win64 the Spooler Service will produce an Error with the ErrorCode 0x000006be, on win32 the normal AddPrinter Dialog will appear.

The source attached provides a basic dll, wich will do nothing but write some information to C:\TMP\DEBUG.TXT if that file is existant (so please create it first!)

The Source is:

------------Start

library PMon64;
{$mode Delphi}
{$H+}
uses Windows, Sysutils;
type
   pMonitor=^rMonitor;
   TEnumPortsFunc=function(pName:LPWSTR;dwLevel:DWORD;pPorts:LPBYTE;
                           cbBuf:DWORD;pdwNeeded:LPDWORD;
                           pdwReturned:LPDWORD):BOOL;stdcall;
   TOpenPortFunc=function(pName:LPWSTR;H:PHANDLE):BOOL;stdcall;
   TOpenPortExFunc=function(pName,pPrinterName:LPWSTR;H:PHANDLE;
                            _Monitor:pMonitor):BOOL;stdcall;
   TStartDocPortFunc=function(hPort:HANDLE;pPrinterName:LPWSTR;
                              JobID,Level:DWORD;
                              pDocInfo:LPBYTE):BOOL;stdcall;
   TWritePortFunc=function(hPort:HANDLE;pBuffer:LPBYTE;
                           cbBuf:DWORD;pcbWritten:LPDWORD):BOOL;stdcall;
   TReadPortFunc=function(hPort:HANDLE;pBuffer:LPBYTE;cbBuf:DWORD;
                          pcbRead:LPDWORD):BOOL;stdcall;
   TEndDocPortFunc=function(hPort:HANDLE):BOOL;stdcall;
   TClosePortFunc=function(hPort:HANDLE):BOOL;stdcall;
   TAddPortFunc=function(pName:LPWSTR;h:HWND;
                         pMonitorName:LPWSTR):BOOL;stdcall;
   TAddPortExFunc=function(pName:LPWSTR;Level:DWORD;pBuffer:LPBYTE;
                           pMonitorName:LPWSTR):BOOL;stdcall;
   TConfigurePortFunc=function(pName:LPWSTR;h:HWND;
                               pMonitorName:LPWSTR):BOOL;stdcall;
   TDeletePortFunc=function(pName:LPWSTR;h:HWND;
                            pMonitorName:LPWSTR):BOOL;stdcall;
   TGetPrinterDataFromPortFunc=function(hPort:HANDLE;ControlID:DWORD;
                                      pValueName,lpInBuffer:LPWSTR;
                                      cbInBuffer:DWORD;
                                      lpOutBuffer:LPWSTR;
                                      cbOutBuffer:DWORD;
                                      lpcbReturned:LPDWORD):BOOL;stdcall;
   TSetPortTimeOutsFunc=function(hPort:HANDLE;lpTCO:pCommTimeouts;
                                 reserved:DWORD):BOOL;stdcall;
   TXcvOpenPortFunc=function(pszObject:LPCWSTR;GrantedAccess:ACCESS_MASK;
                             phXcv:PHANDLE):BOOL;stdcall;
   TXcvDataPortFunc=function(hXcv:HANDLE;pszDataName:LPCWSTR;
                             pInputData:PBYTE;cbInputData:DWORD;
                             pOutputData:PBYTE;cbOutputData:DWORD;
                             pcbOutputNeeded:PDWORD):DWORD;stdcall;
   TXcvClosePortFunc=function(hXcv:HANDLE):BOOL;stdcall;
   rMonitor=packed record
     pfnEnumPorts: TEnumPortsFunc;
     pfnOpenPort: TOpenPortFunc;
     pfnOpenPortEx: TOpenPortExFunc;
     pfnStartDocPort: TStartDocPortFunc;
     pfnWritePort: TWritePortFunc;
     pfnReadPort: TReadPortFunc;
     pfnEndDocPort: TEndDocPortFunc;
     pfnClosePort: TClosePortFunc;
     pfnAddPort: TAddPortFunc;
     pfnAddPortEx: TAddPortExFunc;
     pfnConfigurePort: TConfigurePortFunc;
     pfnDeletePort: TDeletePortFunc;
     pfnGetPrinterDataFromPort: TGetPrinterDataFromPortFunc;
     pfnSetPortTimeOuts: TSetPortTimeOutsFunc;
     pfnXcvOpenPort: TXcvOpenPortFunc;
     pfnXcvDataPort: TXcvDataPortFunc;
     pfnXcvClosePort: TXcvClosePortFunc;
   end;
   rMonitorEx=packed record
     dwMonitorSize:DWORD;
     Monitor:rMonitor;
   end;
   pMonitorEx=^rMonitorEx;
var
   Mon:rMonitorEx;
procedure DbgSend(Text:String);
var f:Textfile;
begin
   if FileExists('C:\TMP\DEBUG.TXT') then begin
     AssignFile(f,'C:\TMP\DEBUG.TXT');
     Append(f);
     Writeln(f,FormatDateTime('HH:MM:SS',now())+': '+Trim(Text));
     CloseFile(f);
   end;
end;
function EnumPorts(pName:LPWSTR;dwLevel:DWORD;pPorts:LPBYTE;
                    cbBuf:DWORD;pdwNeeded:LPDWORD;
                    pdwReturned:LPDWORD):BOOL;stdcall;
begin
   DbgSend('EnumPorts');
end;
function OpenPort(pName:LPWSTR;H:PHANDLE):BOOL;stdcall;
begin
   DbgSend('OpenPort');
end;
function StartDocPort(hPort:HANDLE;pPrinterName:LPWSTR;
                       JobID,Level:DWORD;pDocInfo:LPBYTE):BOOL;stdcall;
begin
   DbgSend('StartDocPort');
end;
function WritePort(hPort:HANDLE;pBuffer:LPBYTE;cbBuf:DWORD;
                    pcbWritten:LPDWORD):BOOL;stdcall;
begin
   DbgSend('WritePort');
end;
function ReadPort(hPort:HANDLE;pBuffer:LPBYTE;cbBuf:DWORD;
                   pcbRead:LPDWORD):BOOL;stdcall;
begin
   DbgSend('ReadPort');
end;
function EndDocPort(hPort:HANDLE):BOOL;stdcall;
begin
   DbgSend('EndDocPort');
end;
function ClosePort(hPort:HANDLE):BOOL;stdcall;
begin
   DbgSend('ClosePort');
end;
function AddPort(pName:LPWSTR;h:HWND;pMonitorName:LPWSTR):BOOL;stdcall;
begin
   DbgSend('AddPort');
end;
function AddPortEx(pName:LPWSTR;Level:DWORD;pBuffer:LPBYTE;
                    pMonitorName:LPWSTR):BOOL;stdcall;
begin
   DbgSend('AddPortEx');
end;
function ConfigurePort(pName:LPWSTR;h:HWND;
                        pMonitorName:LPWSTR):BOOL;stdcall;
begin
   DbgSend('ConfigurePort');
end;
function DeletePort(pName:LPWSTR;h:HWND;
                     pMonitorName:LPWSTR):BOOL;stdcall;
begin
   DbgSend('DeletePort');
end;
function InitializePrintMonitor(pRegRoot:LPWSTR):pMonitorEx;stdcall;export;
begin
   DbgSend('InitializePrintMonitor start');
   ;
   DbgSend('InitializePrintMonitor end');
end;
exports InitializePrintMonitor;
begin
   DbgSend('MainSection start');
   Mon.dwMonitorSize:=SizeOf(rMonitor);
   Mon.Monitor.pfnEnumPorts:=EnumPorts;
   Mon.Monitor.pfnOpenPort:=OpenPort;
   Mon.Monitor.pfnOpenPortEx:=nil;
   Mon.Monitor.pfnStartDocPort:=StartDocPort;
   Mon.Monitor.pfnWritePort:=WritePort;
   Mon.Monitor.pfnReadPort:=ReadPort;
   Mon.Monitor.pfnEndDocPort:=EndDocPort;
   Mon.Monitor.pfnClosePort:=ClosePort;
   Mon.Monitor.pfnAddPort:=AddPort;
   Mon.Monitor.pfnAddPortEx:=AddPortEx;
   Mon.Monitor.pfnConfigurePort:=ConfigurePort;
   Mon.Monitor.pfnDeletePort:=DeletePort;
   Mon.Monitor.pfnGetPrinterDataFromPort:=nil;
   Mon.Monitor.pfnSetPortTimeOuts:=nil;
   Mon.Monitor.pfnXcvOpenPort:=nil;
   Mon.Monitor.pfnXcvDataPort:=nil;
   Mon.Monitor.pfnXcvClosePort:=nil;
   DbgSend('MainSection end');
end.

------------End

I compiled it by the command
32Bit:
fpc -WB0 -MDelphi -B -O- -Os -CX -g- -XDs -Pi386 -TWin32 -vewi PMon64.lpr

and 64Bit.
fpc -WB0 -MDelphi -B -O- -Os -CX -g- -XDs -Px86_64 -TWin64 -vewi PMon64.lpr

The debug.txt on 32 Bit reads:
20:11:37: MainSection start
20:11:37: MainSection end
20:11:37: InitializePrintMonitor start
20:11:37: InitializePrintMonitor end
20:11:37: EnumPorts

The debug.txt on 64 Bit reads:
20:11:37: MainSection start
20:11:37: MainSection end
20:11:37: InitializePrintMonitor start
20:11:37: InitializePrintMonitor end
--> The EnumPorts-Entry is missing here!

so the crash is before or on calling the EnumPorts-Function.

So, anyone an Idea what I might have missed? Or is ther a bug in FPC for Win64?

Any help would be appreciated.

Regards
Lukas

-------------------------- software security networks Lukas Gradl <fpc#ssn.at> Eduard-Bodem-Gasse 5 A - 6020 Innsbruck Tel: +43-512-214040-0 Fax: +43-512-214040-21 --------------------------
Marc Weustink
to Lukas Gradl
Lukas Gradl wrote 8 lines
Hi! I'm having serious troubles compiling a DLL for 64bit Windows. I'm using FPC svn 14444 (Ver 2.5.1) on all machines. I tried on WinXP 32bit (works), Vista 64bit (doesn't work), Win7 32Bit (works) and Win7 64bit (doesn't work). rMonitor=packed record

...

Show quoted text 6 lines
end; rMonitorEx=packed record dwMonitorSize:DWORD; Monitor:rMonitor; end;

Are you sure the C record is packed too ? This would mean that all function pointers in rMonitor are not aligned.

Marc

Lukas Gradl
to Marc Weustink
Show quoted text 11 lines
> rMonitor=packed record ... > end; > > rMonitorEx=packed record > dwMonitorSize:DWORD; > Monitor:rMonitor; > end; Are you sure the C record is packed too ? This would mean that all function pointers in rMonitor are not aligned.

I'm not shure about that as I'm not that packed record works at 32bit -so I thought that should be correct.

Is there a difference between 64Bit and 32Bit?

Here is the orginal C definition, could someone take a look at this:

typedef struct _MONITOR {
BOOL (WINAPI *pfnEnumPorts)
(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,

         LPDWORD pcbNeeded, LPDWORD pcReturned);
   BOOL (WINAPI *pfnOpenPort)
        (LPWSTR pName, PHANDLE pHandle);
   BOOL (WINAPI *pfnOpenPortEx)
        (LPWSTR  pPortName, LPWSTR pPrinterName, PHANDLE pHandle,
         struct _MONITOR FAR *pMonitor);
   BOOL (WINAPI *pfnStartDocPort)
        (HANDLE hPort, LPWSTR pPrinterName, DWORD JobId,
         DWORD Level, LPBYTE  pDocInfo);
   BOOL (WINAPI *pfnWritePort)
        (HANDLE hPort, LPBYTE pBuffer, DWORD cbBuf,
         LPDWORD pcbWritten);
   BOOL (WINAPI *pfnReadPort)
        (HANDLE hPort, LPBYTE pBuffer, DWORD cbBuffer,
         LPDWORD pcbRead);
   BOOL (WINAPI *pfnEndDocPort)
        (HANDLE hPort);
   BOOL (WINAPI *pfnClosePort)
        (HANDLE hPort);
   BOOL (WINAPI *pfnAddPort)
        (LPWSTR pName, HWND hWnd, LPWSTR pMonitorName);
   BOOL (WINAPI *pfnAddPortEx)
        (LPWSTR pName, DWORD Level, LPBYTE lpBuffer,
         LPWSTR lpMonitorName);
   BOOL (WINAPI *pfnConfigurePort)
        (LPWSTR pName, HWND hWnd, LPWSTR pPortName);
   BOOL (WINAPI *pfnDeletePort)
        (LPWSTR pName, HWND hWnd, LPWSTR pPortName);
   BOOL (WINAPI *pfnGetPrinterDataFromPort)
        (HANDLE hPort, DWORD ControlID, LPWSTR pValueName,
         LPWSTR lpInBuffer, DWORD cbInBuffer, LPWSTR lpOutBuffer,
         DWORD cbOutBuffer, LPDWORD lpcbReturned);
   BOOL (WINAPI *pfnSetPortTimeOuts)
        (HANDLE hPort, LPCOMMTIMEOUTS lpCTO,
         DWORD reserved    // must be set to 0);
   BOOL (WINAPI *pfnXcvOpenPort)
        (LPCWSTR pszObject, ACCESS_MASK GrantedAccess, PHANDLE phXcv);
   DWORD (WINAPI *pfnXcvDataPort)
         (HANDLE  hXcv, LPCWSTR pszDataName, PBYTE pInputData,
          DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
          PDWORD pcbOutputNeeded);
   BOOL (WINAPI *pfnXcvClosePort)
        (HANDLE  hXcv);

} MONITOR, FAR *LPMONITOR;

typedef struct _MONITOREX {
   DWORD  dwMonitorSize;
   MONITOR  Monitor;
} MONITOREX, FAR *LPMONITOREX;

regards
Lukas

-------------------------- software security networks Lukas Gradl <fpc#ssn.at> Eduard-Bodem-Gasse 5 A - 6020 Innsbruck Tel: +43-512-214040-0 Fax: +43-512-214040-21 --------------------------
Jonas Maebe
to Lukas Gradl
Lukas Gradl wrote 13 lines
> > rMonitor=packed record > ... >> end; >> >> rMonitorEx=packed record >> dwMonitorSize:DWORD; >> Monitor:rMonitor; >> end; > Are you sure the C record is packed too ? This would mean that all > function pointers in rMonitor are not aligned. I'm not shure about that as I'm not that packed record works at 32bit -so I thought that should be correct.

You must never use a "packed" record for a C record, unless it is declared in C using __attribute__((__packed__)). The fact that it worked in 32 bit was pure coincidence. You also have to add {$packrecords c} to your source file to tell the compiler to lay out records the same way as C compilers to guarantee interoperability.

Jonas

Lukas Gradl
to Jonas Maebe
Show quoted text 6 lines
You must never use a "packed" record for a C record, unless it is declared in C using __attribute__((__packed__)). The fact that it worked in 32 bit was pure coincidence. You also have to add {$packrecords c} to your source file to tell the compiler to lay out records the same way as C compilers to guarantee interoperability.

Jonas, Marc, if you ever come near my place feel free to come along for a beer or something...

Never heard of the $packrecords switch, but that was it - now it works for 32 and 64 bits...

regards
Lukas

-------------------------- software security networks Lukas Gradl <fpc#ssn.at> Eduard-Bodem-Gasse 5 A - 6020 Innsbruck Tel: +43-512-214040-0 Fax: +43-512-214040-21 --------------------------
Reimar Grabowski
to Lukas Gradl: I'm not shure about that as I'm not that packed record works at 32bit -so I thought that…
I'm not shure about that as I'm not that packed record works at 32bit -so I thought that should be correct.

If it works on 32bit it should be correct.

Is there a difference between 64Bit and 32Bit?

Yes.
Some types have different sizes and even the alignment is different for some types. For details look here: http://www.x86-64.org/documentation.html

Here is the orginal C definition, could someone take a look at this:

I cannot help you directly but I can give you a hint based on my experience with C-headers on 64-bit. First you should check what types these typedefs like DWORD actually are. After that you can use the corresponding type from the ctypes unit of FPC. This is the easiest way I found to make my C-headers work correctly on 64-bit as types defined in this unit have the correct sizes and alignments. For example DWORD is actually unsigned long, AFAIK. This would be culong in the ctypes unit.

hope it helps
R.

A: Because it messes up the order in which people normally read text. Q: Why is top-posting such a bad thing? A: Top-posting. Q: What is the most annoying thing in e-mail?
Reimar Grabowski
to Reimar Grabowski
Show quoted text 6 lines
On Fri, 18 Dec 2009 13:39:45 +0100 Lukas Gradl wrote: > I'm not shure about that as I'm not that packed record > works at 32bit -so I thought that should be correct. If it works on 32bit it should be correct.

This is wrong. See Joosts mail. Of course the compiler directive he gave is the correct way.

R.

A: Because it messes up the order in which people normally read text. Q: Why is top-posting such a bad thing? A: Top-posting. Q: What is the most annoying thing in e-mail?