2009-09-09 41 views
7

Tôi đang cố gắng sử dụng một dll C++ từ một chương trình gốc. Tôi đang theo kịch bản phương pháp ảo như được giải thích hereDelphi PChar đến C++ const char *

phép nói rằng C++ chức năng chữ ký của tôi có dạng

int Setup(const char* szIp, const char* szPort); 

Và chữ ký delphi tương ứng là

function Setup(ip, port: PChar):Integer: virtual; cdecl; abstract; 

Và ở đâu đó từ chương trình delphi tôi có thể gọi

pObj.Setup('192.168.1.100', '97777'); 

c ontrol đi vào dll, nhưng szIp và szPort thông số chính thức chỉ nhận được ký tự đầu tiên của ip và cổng mà tôi đã vượt qua từ chương trình delphi.

Tôi hiểu rằng nó có liên quan đến việc vô hiệu hóa chuỗi đúng cách trong delphi. Vì vậy, tôi đã thử những điều sau đây quá.

var 
    pzIp, pzPort: PChar; 
    szIp, szPort: string; 

begin 
    szIp := '192.168.1.2'; 
    szPort := '9777'; 
    //initilize memory for pchar vars 
    GetMem(pzIp, Length(szIp)+1); 
    GetMem(pzPort, Length(szPort)+1); 
    //null terminate the strings 
    pzIp[Length(szIp)+1] := #0; 
    pzPort[Length(szPort)+1] := #0; 
    //copy strings to pchar 
    StrPCopy(pzIp, szIp); 
    StrPCopy(pzPort, szPort); 
end. 

Điều này cũng hoạt động. Khi tôi WritelnpzIppzPort Tôi nhận được kết quả lạ.

Quên để nói, tất cả các chức năng thành viên từ ++ dll C được biên soạn với __stdcall và xuất khẩu đúng

Trả lời

17

Trong Delphi 2010 (và Delphi 2009) kiểu "char" thực sự là một WIDEChar - tức là, rộng 16 bit. Vì vậy, khi bạn gọi hàm C++ của bạn, nếu đó là mong đợi CHAR được 8 bit rộng (được gọi là "ANSI", chứ không phải là UNICODE), sau đó nó sẽ giải thích sai thông số đầu vào.

ví dụ: nếu bạn vượt qua chuỗi 'ABC' # 0 (Tôi đang hiển thị dấu kết vô hiệu một cách rõ ràng nhưng đây chỉ là một phần ẩn của một chuỗi trong Delphi và không cần phải được thêm cụ thể), hãy chuyển con trỏ đến 8 byte trình tự, KHÔNG 4 byte!

Nhưng vì 3 ký tự trong chuỗi của bạn chỉ có giá trị mã điểm 8-bit (về Unicode, điều này có nghĩa rằng những gì C++ code "nhìn thấy" là một chuỗi trông giống như:

'A'#0'B'#0'C'#0#0#0 

Điều này sẽ giải thích tại sao mã C++ của bạn dường như chỉ nhận được ký tự đầu tiên của chuỗi - nó đang nhìn thấy # 0 trong byte thứ hai của ký tự đầu tiên đó và giả sử rằng nó là bộ kết thúc null cho toàn bộ chuỗi.

Bạn có thể cần phải sửa đổi C++ code để nhận được một cách chính xác các con trỏ tới WideChar chuỗi, hoặc sửa đổi các chữ ký chức năng trong Delphi và chuyển đổi dây của bạn để AnsiString trong mã Delphi trước đi qua những sang C++ chức năng :

chức năng chữ ký Revised:

function Setup(ip, port: PANSIChar):Integer: virtual; stdcall; abstract; 

và tương ứng với "bàn tay Long" thể hiện chuyển đổi các chuỗi để Một NSIString trước khi gọi hàm - trình biên dịch có thể chăm sóc này cho bạn, nhưng bạn có thể tìm thấy nó hữu ích để làm cho nó rõ ràng trong mã của bạn chứ không phải là dựa vào "biên dịch ma thuật":

var 
    sIPAddress: ANSIString; 
    sPort: ANSIString; 
    begin 
    sIPAddress := '192.168.1.100'; 
    sPort  := '97777'; 

    pObj.Setup(sIPAddress, sPort); 

    // etc... 
+0

Cảm ơn bạn đã giải thích chi tiết hơn: câu trả lời của tôi là một suy nghĩ nhanh chóng đã chứng minh đúng, nhưng tôi khuyên đây là câu trả lời để được chấp nhận. – IanH

+0

Cảm ơn @Deltics, đã hoạt động. Một thay đổi nhỏ mặc dù, cần thiết để được đúc để làm cho chương trình delphi biên dịch pObj.Setup (PAnsiChar (sIPAddress), PAnsiChar (sPort)); Đặc biệt cảm ơn @IanH – rptony

3

Nếu tôi hiểu đúng nguyên mẫu hàm của bạn nên stdcall là tốt.

function Setup(ip, port: PChar):Integer: virtual; stdcall; abstract; 

ps. Các chuỗi Delphi đã bị vô hiệu hóa.

+0

hmm, nó không đã làm việc. Cùng một kết quả. Nhưng tôi có thể thoát khỏi sự cố vi phạm quyền truy cập khi hàm C++ trả về. Vì vậy, tôi đoán tôi đang tiến bộ :) – rptony

+0

thời gian để thả để xem lắp ráp :) –

+0

làm cho nó stdcall đã cho tôi giải quyết vài vấn đề khác quá, 1 cho tip – rptony

4

Char có cùng kích thước trong cả hai trình biên dịch không? Nếu bạn đang sử dụng D2009/D2010, char hiện là 16 bit.

+0

yeah tôi đang sử dụng D2010. Và mã C++ của tôi là 32 bit. Vì vậy, kích thước nhân vật phải phù hợp với quyền? – rptony

+2

Không nhất thiết: BCB4 là trình biên dịch C++ 32 bit, nhưng char là một byte. Bạn có thể vô hiệu hóa chuỗi của bạn sớm với 0 byte cao cho ký tự đầu tiên. Hãy thử thay đổi mã thử nghiệm ở trên để khai báo szIP và szPort là AnsiString thay vì chuỗi. – IanH

+0

bỏ phiếu để dẫn đầu câu trả lời – rptony

Các vấn đề liên quan