Returning Binary Data from ActiveX to SQL Server varbinary(max)
The error -2147211494 (hex 0x80040202) in SQL Server when using “sp_OAMethod” typically indicates a type mismatch or invalid data type issue, particularly when interacting with COM objects that return binary data.
The Chilkat ActiveX returns a SAFEARRAY of VT_UI1, which causes the problem explained below. The solution is to instead look for the Chilkat method that returns the binary data as base64. For example, if we have a BinData, you can instead get the base64 data by calling GetEncoded as shown here:
- See further below for information about how to convert a base64 string to varbinary(max)
- Also beware of limitations on lengths of strings returned from sp_OAMethod. See SQL sp_OAMethod String Length Return Value Limitations
- The following code snippet is for strings that are not too large. See SQL sp_OAMethod String Length Return Value Limitations for the workaround to return larger strings.
- In summary, to get a large amount of binary data into a varbinary(max), you’ll need to return the data as base64 using the workaround explained in the linked post above, then convert the base64 to binary as described below. In general SQL Server is a massive pain in the ass when dealing with large strings or binary data.
CREATE PROCEDURE ChilkatSample AS BEGIN DECLARE @hr int -- Important: Do not use nvarchar(max). See the warning about using nvarchar(max). DECLARE @sTmp0 nvarchar(4000) DECLARE @bd int -- Use "Chilkat_9_5_0.BinData" for versions of Chilkat < 10.0.0 EXEC @hr = sp_OACreate 'Chilkat.BinData', @bd OUT IF @hr <> 0 BEGIN PRINT 'Failed to create ActiveX component' RETURN END DECLARE @success int EXEC sp_OAMethod @bd, 'LoadFile', @success OUT, 'qa_data/jpg/starfish.jpg' IF @success = 0 BEGIN PRINT 'Failed to load file.' EXEC @hr = sp_OADestroy @bd RETURN END EXEC sp_OAMethod @bd, 'GetEncoded', @sTmp0 OUT, 'base64' PRINT @sTmp0 EXEC @hr = sp_OADestroy @bd END
In the context of “sp_OAMethod” and binary data, this usually means that SQL Server is expecting one data type, but the COM method is returning a different one or the data returned is not being handled correctly by SQL Server.
Common Causes and Solutions for 0x80040202:
Here’s a breakdown of the likely causes and how to resolve them:
1. Incorrect Data Type Handling:
- 0x80040202 is often associated with mismatched data types when using OLE Automation Procedures in SQL Server.
- If the COM method you are calling returns a binary array (like a “SAFEARRAY” of “VT_UI1”), SQL Server needs to handle it as a “VARBINARY”.
- This error can occur if the data returned by the ActiveX method is not directly convertible to the type expected by “sp_OAMethod”.Solution:
- Ensure that the ActiveX method is designed to return a “byte” array (“VT_ARRAY | VT_UI1”) if you want to store it as “VARBINARY” in SQL Server.
- If the ActiveX method returns a different VARIANT type, such as “VT_BSTR” (string), you may need to modify the method or write a wrapper to convert it to the correct format before calling it from SQL Server.
2. Handling SAFEARRAY Properly:
- When dealing with binary data in ActiveX methods, the data is often returned as a “SAFEARRAY” of bytes (“VT_ARRAY | VT_UI1”).
- SQL Server has limited support for handling SAFEARRAY directly through “sp_OA*” procedures. If the COM object is returning data as a SAFEARRAY of bytes, SQL Server might not be able to process it correctly.Solution:
- You may need to modify your ActiveX component to convert the binary data into a hex-encoded string or Base64 string before returning it to SQL Server.
- Then, you can convert the hex-encoded or Base64 string back to “VARBINARY” inside SQL Server using functions like “CAST” or “CONVERT”.Example:
- If your ActiveX component returns a Base64-encoded string:
DECLARE @base64String NVARCHAR(MAX); DECLARE @binaryData VARBINARY(MAX); EXEC sp_OAMethod @object, 'GetBase64Data', @base64String OUTPUT; SET @binaryData = CAST('' AS XML).value('xs:base64Binary(sql:variable("@base64String"))', 'VARBINARY(MAX)'); INSERT INTO YourTable (YourBinaryColumn) VALUES (@binaryData);
3. COM Component Error:
- Sometimes, 0x80040202 can occur due to an issue with the COM component itself.
- It may be failing internally while trying to return the data, especially if it is not able to correctly serialize the binary data.Solution:
- Test the COM method independently outside of SQL Server, such as using a VBScript or PowerShell to verify that it correctly returns the expected binary data.
- Ensure that the COM object is registered properly and that it behaves as expected when returning binary data.
4. Missing or Improper Data Initialization:
- This error can also occur if the output parameter in “sp_OAMethod” is not properly initialized to receive the data from the COM method.
- Make sure that the output parameter is defined correctly in your “sp_OAMethod” call.Solution:
- Ensure that you have declared the output parameter as “VARBINARY” if it is intended to receive binary data.
- Confirm that the COM method expects to return a “byte” array or another compatible type.
Example of Correctly Handling Binary Data:
If your ActiveX method is supposed to return binary data, you might use the following approach:
DECLARE @object INT; DECLARE @binaryData VARBINARY(MAX); DECLARE @hr INT; -- Create the COM object (replace 'YourActiveX.ProgID' with actual ProgID) EXEC @hr = sp_OACreate 'YourActiveX.ProgID', @object OUT; IF @hr <> 0 BEGIN PRINT 'Error creating ActiveX object'; RETURN; END; -- Call the method that returns binary data as Base64 (modify as needed) DECLARE @base64String NVARCHAR(MAX); EXEC @hr = sp_OAMethod @object, 'GetBase64EncodedData', @base64String OUT; IF @hr <> 0 BEGIN PRINT 'Error calling ActiveX method'; EXEC sp_OADestroy @object; RETURN; END; -- Convert the Base64 string to VARBINARY SET @binaryData = CAST('' AS XML).value('xs:base64Binary(sql:variable("@base64String"))', 'VARBINARY(MAX)'); -- Store the binary data in your table INSERT INTO YourTable (YourVarbinaryColumn) VALUES (@binaryData); -- Clean up EXEC sp_OADestroy @object;
Summary:
- Error 0x80040202 usually indicates a type mismatch when handling the data returned from a COM method.
- Verify that the ActiveX method returns a data type that is compatible with what SQL Server can handle (“VT_ARRAY” of “VT_UI1” for binary).
- Consider converting binary data into a Base64-encoded string or hex string before returning it to SQL Server, then decoding it back to “VARBINARY”.
- Test the COM method independently and ensure the output is what SQL Server expects to handle.