2010-07-12 3 views
2

WinInet을 사용하여 Google 서버 중 하나에서 정보를 검색하고 연결합니다. 다음을 사용하고 있습니다.델파이의 동적 배열과 wininet?

indexdata: array of byte[1..5000] of byte; 
infoBuffer: array [0..5000] of char; 
BufferSize: DWORD; 
reserved: DWORD; 
text: string; 

BufferSize := Length(infoBuffer); 
res := HttpQueryInfo(hHttpRequest, HTTP_QUERY_RAW_HEADERS_CRLF, @infoBuffer, BufferSize, Reserved); 

Reserved := 0; 
InternetReadFile(hHttpRequest, @indexdata, sizeof(indexdata), Reserved); 

SetLength(text, Reserved); 
CopyMemory(@text[1], @indexdata[1], Reserved); 

두 바이트 배열은 지금까지 충분했습니다. 상황이 바뀌 었습니다. 서버는 이제 5000보다 크거나 작은 정보를 반환 할 수 있습니다. 최악의 경우, InternetReadFile에서는 infoBuffer에서 가변 크기를 반환 할 수 있습니다.

그래서 인덱스 데이터 및 infobuffer 바이트 배열로 선언하고 SetLength 해당 길이를 설정할 사용했지만 2 일이 일어났습니다.

1) 나는 아직도 서버가 내가 제대로 말,로 설정할 수 없습니다 때문에 돌려 보낼 INDEXDATA의 크기를 모르는, 100000

2) 지금)에서 CopyMemory 통과로 난 (사용할 수 없습니다 인덱스 데이터를 간단한 문자열 변수에 복사하여 데이터를 사용할 수 있도록하는 낮은 (인덱스 데이터).

어떻게 이것을 델파이에서 처리합니까? 나는 C로 할 수 있지만 델파이에서 제대로 할 수없는 것 같습니다.

코드가 인정됩니다.

감사합니다!

+1

'예약 됨'은 다소 나쁜 변수 이름입니다. 'lpdwNumberOfBytesRead'는 어떨까요? –

+1

... 또는 약간 더 읽기 쉬운 "InputSize"? : P –

+0

@andreas 확실히, 내가 그것을 바꿀 것이다 – Jessica

답변

3

당신은 char 델파이 2009 년부터 유니 코드 문자하지만 stringUnicodeString 아닌 AnsiString 델파이 2009 년에 같은 방법으로 델파이 2009에 앞서 ANSI 문자라는 것을 알고있다.

따라서 SetLength(text, Reserved)을 쓸 때 text의 문자 수를 Reserved으로 설정하십시오. 그러나 바이트 수는 2*Reserved이됩니다.

즉, Delphi 2009+에서 charbyte이 아닌 2 바이트입니다.

모두 char을 모두 AnsiChar으로 바꾸고 모두 stringAnsiString으로 바꿔 이전 동작을 되돌릴 수 있습니다. 당신이 당신의 전체 코드를 게시하지 않았기 때문에

업데이트

, 정말 문제가 무엇인지 말할 수 없습니다. 그럼에도 불구하고 Delphi에서 InternetReadFile의 사용 예를 읽는 것이 흥미로울 수 있습니다. 내 대답은 this question입니다. Delphi 및 InternetReadFile을 사용하여 인터넷에서 텍스트 파일을 읽는 방법에 대한 완전한 예제입니다. 당신적이고 들어

, 나는뿐만 아니라 아래에 내 코드를 붙여 넣습니다

는 인터넷에서 데이터를 읽을 InternetReadFile 기능을 사용하려면.

function WebGetData(const UserAgent: string; const Server: string; const Resource: string): string; 
var 
    hInet: HINTERNET; 
    hURL: HINTERNET; 
    Buffer: array[0..1023] of AnsiChar; 
    i, BufferLen: cardinal; 
begin 
    result := ''; 
    hInet := InternetOpen(PChar(UserAgent), INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0); 
    try 
    hURL := InternetOpenUrl(hInet, PChar('http://' + Server + Resource), nil, 0, 0, 0); 
    try 
     repeat 
     InternetReadFile(hURL, @Buffer, SizeOf(Buffer), BufferLen); 
     if BufferLen = SizeOf(Buffer) then 
      result := result + AnsiString(Buffer) 
     else if BufferLen > 0 then 
      for i := 0 to BufferLen - 1 do 
      result := result + Buffer[i]; 
     until BufferLen = 0; 
    finally 
     InternetCloseHandle(hURL); 
    end; 
    finally 
    InternetCloseHandle(hInet); 
    end; 
end; 

샘플 사용 : 내가 인터넷에서 작은 (한 줄) 텍스트 파일을 읽을 수있는 다음 코드를 사용

WebGetData('My UserAgent', 'www.rejbrand.se', '/MyDir/update/ver.txt') 
+0

저는 delphi 7을 사용하고 있습니다. 그러나 설명을 주신 덕분에 – Jessica

+1

@Jessica, Andreas의 제안을 즉시 구현해야합니다. 선언을 AnsiString으로 변경하고 아무 것도 부수 지 않고, 새로운 델파이로 이동하면 재 작업 할 필요가 없습니다. AnsiString/AnsiChar로 선언 할 때 단점이 없습니다. –

+0

좋습니다, 감사합니다. 아직도 이것은 내 질문에 대답하지 않습니다. – Jessica

1

대신에서 CopyMemory의를,과 같이, 이동 루틴을 사용해보십시오 :

Move(indexdata[1], text[1], reserved); 

(예 : @ 기호 없음) 문제 2를 해결해야합니다. 문제 # 1은 귀하와 서버 사이에 있습니다. 상한값이 반환 할 크기에 대해 알 수있는 방법이 필요하며 버퍼를 적어도 그렇게 크게 만들어야합니다. 문서에서이를 찾을 수 있거나, 들어오는 데이터의 크기를 알려주는 다른 API를 먼저 호출 할 수 있어야합니다.

또한 거기에 약간의 확인을하여 버퍼보다 ​​큰 값을 반환하면 즉시 예외가 발생합니다. 버퍼가 오버런되면 프로그램이 공격 받고 있다고 가정해야합니다.

+0

"이동"은 예외로 실패합니다 : 주소 xxxxx의 액세스 위반 .... 주소 yyyyy의 읽기 – Jessica

+0

먼저 SetLength를 호출 했습니까? SetLength를 호출하고 @s를 사용하지 않고'text'의 크기를 초과하지 않는다면, 그것은 일어나서는 안됩니다. –

+1

@Jessica : "CopyMemory"와 "move"의 유일한 차이점은 "@"의 부족이 아니라는 점입니다. 두 개의 첫 번째 인수는 다른 순서 (Destionation, Source) 대 (Source, Destination)! 덕분에 –

1

알 수없는 크기의 버퍼를 반환하는 Windows 함수는 너무 작은 버퍼가 전달되는 경우 일반적으로 버퍼의 요구 크기를 반환합니다. 이렇게하면 큰 데이터를 저장할만큼 큰 버퍼를 미리 크기 조정할 필요가 없습니다. 작은 버퍼 (길이가 0 인 경우에도)를 전달하면 함수는 버퍼의 크기를 반환합니다. 그런 다음 버퍼의 크기를 조정하고 다시 데이터를 읽는 함수를 전달할 수 있습니다. 예를 들어 MSDN의 HttpQueryInfo() 설명을 확인하십시오. Delphi에서 알 수없는 크기의 버퍼를 처리하려면 두 가지 방법이 있습니다.

: 매우 모두 당신이 예를 들어

C.에서하는, GetMem으로()와 FreeMem()를 사용하여

  • 를 사용하여 동적 배열 및 SetLength를()
  • 를 사용하여 동적으로 할당 된 버퍼
    var 
        Buf: Pointer; 
        BufSize: DWORD; 
        Rez: DWORD; 
        ... 
    const 
        InitialBufSize = 1024; 
    
    ... 
    BufSize := InitialBufSize; 
    GetMem(Buf, BufSize); 
    try 
        if not HttpQueryInfo(hRequest, dwInfoLevel, Buf, BufSize, lpdwIndex) then 
        begin 
        Rez := GetLastError; 
        if Rez = ERROR_INSUFFICIENT_BUFFER then 
        begin 
         FreeMem(Buf, InitialBufSize); 
         GetMem((Buf, BufSize); 
         if not HttpQueryInfo(hRequest, dwInfoLevel, Buf, BufSize, lpdwIndex) then 
         Rez := GetLastError 
        end; 
    ... 
    finally 
        FreeMem(Buf, BufSize); 
    end;