2008-09-16 29 views
5

Tôi có một đối tượng BSTR mà tôi muốn chuyển đổi để sao chép vào một đối tượng wchar__t. Điều khó khăn là độ dài của đối tượng BSTR có thể ở bất cứ đâu từ vài kilobyte đến vài trăm kilobyte. Có cách sao chép dữ liệu hiệu quả không? Tôi biết tôi chỉ có thể tuyên bố một mảng wchar_t và phân phối các dữ liệu tối đa có thể nó sẽ bao giờ cần phải giữ. Tuy nhiên, điều này có nghĩa là phân bổ hàng trăm kilobyte dữ liệu cho một thứ có khả năng chỉ cần vài kilobyte. Bất kỳ đề xuất?Làm thế nào để bạn sao chép hiệu quả BSTR vào wchar_t []?

Trả lời

5

Đối tượng BSTR chứa tiền tố độ dài, vì vậy việc tìm hiểu độ dài là giá rẻ. Tìm hiểu chiều dài, phân bổ một mảng mới đủ lớn để giữ kết quả, xử lý vào đó và nhớ giải phóng nó khi bạn hoàn thành.

0

Sử dụng ATL và CStringT thì bạn chỉ có thể sử dụng toán tử gán. Hoặc bạn có thể sử dụng macro USES_CONVERSION, sử dụng phân bổ đống này, vì vậy bạn sẽ chắc chắn rằng bạn sẽ không bị rò rỉ bộ nhớ.

4

Không bao giờ cần chuyển đổi. Một con trỏ BSTR trỏ đến ký tự đầu tiên của chuỗi và nó bị vô hiệu. Độ dài được lưu trước ký tự đầu tiên trong bộ nhớ. BSTR s luôn là Unicode (UTF-16/UCS-2). Đã có một giai đoạn được gọi là 'ANSI BSTR' - có một số tham chiếu trong các API cũ - nhưng bạn có thể bỏ qua chúng trong sự phát triển hiện tại.

Điều này có nghĩa là bạn có thể chuyển số BSTR an toàn cho bất kỳ chức năng nào mong đợi một số wchar_t.

Trong Visual Studio 2008, bạn có thể gặp lỗi trình biên dịch vì BSTR được định nghĩa là con trỏ đến unsigned short, trong khi wchar_t là kiểu gốc. Bạn có thể truyền hoặc tắt wchar_t tuân thủ /Zc:wchar_t.

+1

wchar_t không được đảm bảo chính xác với kích thước của một đoạn mã ngắn. – ben

+0

Tôi nghĩ hoạt động này luôn an toàn, nhưng có thể không phải lúc nào cũng cho kết quả mong đợi. Một BSTR có thể chứa các ký tự null trong phần thân của nó (do đó tiền tố độ dài), trong khi một hàm mong đợi một wchar_t * sẽ giải thích ký tự null đầu tiên ở cuối chuỗi. – Martin

+8

Bạn không thể "vượt qua một BSTR một cách an toàn cho bất kỳ chức năng mong đợi một wchar_t *". So sánh SysStringLen (NULL) và wcslen (NULL). – Constantin

3

Một điều cần ghi nhớ là các chuỗi BSTR có thể và thường có, chứa các giá trị được nhúng. Một null không có nghĩa là kết thúc của chuỗi.

7

Trước tiên, bạn có thể không thực sự phải làm gì cả, nếu tất cả những gì bạn cần làm là đọc nội dung. Một kiểu BSTR là một con trỏ tới một mảng wchar_t đã kết thúc bằng null. Trong thực tế, nếu bạn kiểm tra các tiêu đề, bạn sẽ thấy rằng BSTR được về cơ bản định nghĩa là:

typedef BSTR wchar_t*; 

Vì vậy, trình biên dịch không thể phân biệt giữa họ, mặc dù họ có ngữ nghĩa khác nhau.

Có hai cảnh báo quan trọng.

  1. BSTRs được cho là không thay đổi. Bạn không bao giờ nên thay đổi nội dung của BSTR sau khi nó đã được khởi tạo. Nếu bạn "thay đổi nó", bạn phải tạo một cái mới gán con trỏ mới và giải phóng con trỏ cũ (nếu bạn sở hữu nó).
    [CẬP NHẬT: điều này không đúng; lấy làm tiếc! Bạn có thể sửa đổi BSTRs tại chỗ; Tôi rất hiếm khi có nhu cầu.]

  2. BSTR được phép chứa các ký tự null được nhúng, trong khi chuỗi C/C++ truyền thống thì không.

Nếu bạn có một số tiền hợp lý của kiểm soát nguồn gốc của BSTR, và có thể đảm bảo rằng các BSTR không có NULLs nhúng, bạn có thể đọc từ BSTR như thể nó là một wchar_t và sử dụng chuỗi thông thường các phương thức (wcscpy, v.v.) để truy cập nó. Nếu không, cuộc sống của bạn trở nên khó khăn hơn. Bạn sẽ phải luôn thao tác dữ liệu của mình dưới dạng nhiều BSTR hơn hoặc dưới dạng mảng được phân bổ động của wchar_t. Hầu hết các hàm liên quan đến chuỗi sẽ không hoạt động chính xác.

Giả sử bạn kiểm soát dữ liệu của mình hoặc đừng lo lắng về NULL. Giả sử rằng bạn thực sự cần tạo một bản sao và không thể đọc trực tiếp BSTR hiện có. Trong trường hợp đó, bạn có thể làm một cái gì đó như thế này:

UINT length = SysStringLen(myBstr);  // Ask COM for the size of the BSTR 
wchar_t *myString = new wchar_t[lenght+1]; // Note: SysStringLen doesn't 
              // include the space needed for the NULL 

wcscpy(myString, myBstr);     // Or your favorite safer string function 

// ... 

delete myString; // Done 

Nếu bạn đang sử dụng giấy gói lớp cho BSTR của bạn, bao bọc nên có một cách để gọi SysStringLen() cho bạn. Ví dụ:

CComBString use .Length(); 
_bstr_t  use .length(); 

CẬP NHẬT: Đây là một bài viết tốt về chủ đề bởi một ai đó hơn rất nhiều hiểu biết hơn tôi:
"Eric [Lippert]'s Complete Guide To BSTR Semantics"

CẬP NHẬT: Thay thế strcpy() với wcscpy() trong ví dụ

+0

AFAIK, BSTRs * không * được cho là không thay đổi. Đó là lý do tại sao họ không tuyên bố const *. – Constantin

+0

Hmmm ... Tôi không thể tìm thấy bất kỳ tài liệu tham khảo nào hỗ trợ vị trí của tôi. Tôi đang nghĩ gì vậy? Tôi sẽ sửa nó. –

+0

bạn không nên sử dụng wcscpy thay vì strcpy? – arolson101

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