BUG: You Cannot Set the Microsoft Message Queuing Body Property by Using the Sp_OASetProperty Stored Procedure (309002)



The information in this article applies to:

  • Microsoft SQL Server 2000 (all editions)

This article was previously published under Q309002
BUG #: 355102 (SHILOH_BUGS)

SYMPTOMS

When you instantiate a Microsoft Message Queuing object by SQL Server and the sp_OA automation stored procedures, you cannot assign the Body parameter a value.

Additionally, you receive the following error message:

NOTE: The script in the "Steps to Reproduce the Problem" section in this article generates this error message.
Operation            hr         Source      Description
-------------------- ---------- ----------- ---------------------------
Set MSMQMessage.Body 0x80070057 MSMQMessage The parameter is incorrect.

(1 row(s) affected)
					

CAUSE

This problem occurs because the Message Queuing object rejects the parameter because it is not the correct type. The body property of the MSMQMessage object expects a data type of VT_BSTR, but SQL Server does not support passing this data type as a parameter.

WORKAROUND

To work around this problem, follow these steps:
  1. In a Transact-SQL context, create a DTS package (that is stored in SQL Server) that sends an Message Queuing message.
  2. Create the following stored procedure that sets the Body property of the Message Queuing message, and that runs the package:
      
    CREATE PROCEDURE send_msmq_message
    @queuename varchar(30),
    @messagetext varchar(50)
    
    AS
    
    SET NOCOUNT ON
    
    DECLARE @packagename varchar(30)
    DECLARE @flag int
    SELECT @packagename = 'MSMQ_send'  --DTS package name goes here
    SELECT @flag = 256 --"integrated security"
    
    --object handles, misc variables
    DECLARE @debug_mode bit  --0=suppress debug msgs, 1=show msgs
    DECLARE @eventdesc char(30)
    DECLARE @resultcode int
    DECLARE @package_handle int
    DECLARE @task_handle int
    DECLARE @property_handle int
    DECLARE @customtask_handle int
    DECLARE @message_handle int
    DECLARE @verified_property varchar(255)
    
    DECLARE @steps_count int
    DECLARE @steps_handle int
    DECLARE @step_handle int
    DECLARE @step_result int
    DECLARE @result_sum int
    
    DECLARE @error_code int
    DECLARE @error_source varchar(8000)
    DECLARE @error_description varchar(8000)
    DECLARE @error_helpfile varchar(8000)
    DECLARE @error_helpcontext int
    DECLARE @error_interface_id varchar(8000)
    
    SELECT @debug_mode = 0
    
    --*************************************
    --establish a Package object
    --*************************************
    EXEC @resultcode = sp_OACreate 'DTS.Package2', @package_handle OUT
    IF @debug_mode = 1 
    	BEGIN
    	SELECT @eventdesc = 'package object built.'
    	SELECT @eventdesc, result = @resultcode, package_handle = @package_handle
     
    	END
    
    IF @resultcode <> 0
    	BEGIN
    	EXEC sp_OAGetErrorInfo @package_handle
    	GOTO Destructor
    
    	END
    --*************************************
    --load the package definition from the server
    --*************************************
    
    EXEC @resultcode = sp_OAMethod @package_handle, 'LoadFromSqlServer', NULL, @ServerName=@@SERVERNAME, @PackageName=@packagename, @Flags=@flag
    IF @debug_mode = 1 
    	BEGIN
    	SELECT @eventdesc = 'load package from SQL Server.'
    	SELECT @eventdesc, result = @resultcode, package_handle = @package_handle
    	 
    	END
    IF @resultcode <> 0
    	BEGIN
    	EXEC sp_OAGetErrorInfo @package_handle
    	GOTO Destructor
    
    	END
    
    --*************************************
    --isolate the first task in the job ("Main Task", a Message Queue Task)
    --*************************************
    
    EXEC @resultcode = sp_OAGetProperty @package_handle, 'Tasks(1)', @task_handle OUTPUT
    IF @debug_mode = 1 
    	BEGIN
    	SELECT @eventdesc = 'isolating the individual task.'
    	SELECT @eventdesc, result = @resultcode, package_handle = @package_handle, task_handle = @task_handle
    	END
    
    IF @resultcode <> 0
    		BEGIN
    		EXEC sp_OAGetErrorInfo @package_handle
    		GOTO Destructor
    
    		END
    
    IF @debug_mode = 1 
            BEGIN
    	EXEC @resultcode = sp_OAGetProperty @task_handle, 'Description', @verified_property OUT
    	SELECT 'result' = @resultcode, 'task desc' = @verified_property
    	END
    --*************************************
    --find the QueuePath property, and set it to the given queue name
    --*************************************
    
    EXEC @resultcode = sp_OAGetProperty @task_handle, 'Properties.Item("QueuePath")', @property_handle OUTPUT
    IF @debug_mode = 1 
    	BEGIN
    	SELECT @eventdesc = 'isolating QueuePath property.'
    	SELECT @eventdesc, result = @resultcode, package_handle = @package_handle, task_handle = @task_handle, property_handle = @property_handle
    	 
    	END
    IF @resultcode <> 0
    	BEGIN
    	EXEC sp_OAGetErrorInfo @task_handle
    	GOTO Destructor
    
    	END
    
    EXEC @resultcode = sp_OASetProperty @property_handle, 'Value', @queuename
    IF @debug_mode = 1 
    	BEGIN
    	SELECT @eventdesc = 'setting the QueuePath value.'
    	SELECT @eventdesc, result = @resultcode, package_handle = @package_handle, task_handle = @task_handle, property_handle = @property_handle, 'queue name' = @queuename
    	END	
    IF @resultcode <> 0
    	BEGIN
    	EXEC sp_OAGetErrorInfo @property_handle
    	GOTO Destructor
    
    	END
    IF @debug_mode = 1 
    	BEGIN
    	EXEC @resultcode = sp_OAGetProperty @property_handle, 'Value', @verified_property OUT
    	SELECT 'result' = @resultcode, 'verified' = @verified_property
    	END
    
    --*************************************
    --find the task's CustomTask property (this object holds the message itself)
    --*************************************
    
    EXEC @resultcode = sp_OAGetProperty @task_handle, 'CustomTask', @customtask_handle OUTPUT
    IF @debug_mode = 1 
    	BEGIN
    	SELECT @eventdesc = 'isolating CustomTask property.'
    	SELECT @eventdesc, result = @resultcode, package_handle = @package_handle, task_handle = @task_handle, customtask_handle = @customtask_handle
    	 
    	END
    IF @resultcode <> 0
    	BEGIN
    	EXEC sp_OAGetErrorInfo @task_handle
    	GOTO Destructor
    
    	END
    
    --*************************************
    --find the Message object (1st item in the Messages collection), and set its MessageString to the given text
    --*************************************
    
    EXEC @resultcode = sp_OAGetProperty @customtask_handle, 'Messages(1)', @message_handle OUTPUT
    IF @debug_mode = 1 
    	BEGIN
    	SELECT @eventdesc = 'isolating the message.'
    	SELECT @eventdesc, result = @resultcode, package_handle = @package_handle, task_handle = @task_handle, customtask_handle = @customtask_handle, message_handle = @message_handle
    	 
    	END
    IF @resultcode <> 0
    	BEGIN
    	EXEC sp_OAGetErrorInfo @package_handle
    	GOTO Destructor
    
    	END
    
    EXEC @resultcode = sp_OASetProperty @message_handle, 'MessageString', @messagetext
    IF @debug_mode = 1 
    	BEGIN
    	SELECT @eventdesc = 'setting the MessageString.'
    	SELECT @eventdesc, result = @resultcode, package_handle = @package_handle, task_handle = @task_handle, customtask_handle = @customtask_handle, message_handle = @message_handle, 'text' = @messagetext
    	END
    	
    IF @resultcode <> 0
    	BEGIN
    	EXEC sp_OAGetErrorInfo @message_handle
    	GOTO Destructor
    
    	END
    
    IF @debug_mode = 1 
    	BEGIN
    	EXEC @resultcode = sp_OAGetProperty @message_handle, 'MessageString', @verified_property OUT
    	SELECT 'result' = @resultcode, 'verified' = @verified_property
    	END
    
    --*************************************
    --run the (now-customized) package
    --*************************************
    EXEC @resultcode = sp_OAMethod @package_handle, 'Execute'
    IF @debug_mode = 1 
    	BEGIN
    	SELECT @eventdesc = 'execute package.'
    	SELECT @eventdesc, result = @resultcode, package_handle = @package_handle
    	 
    	END
    
    IF @resultcode <> 0
    	BEGIN
    	EXEC sp_OAGetErrorInfo @package_handle
    	GOTO Destructor
    
    	END
    --*************************************
    --look for step-level errors
    --*************************************
    
    EXEC @resultcode = sp_OAGetProperty @package_handle, 'Steps', @steps_handle OUTPUT
    IF @resultcode <> 0
    	BEGIN
    	print 'Unable to get steps'
            EXEC sp_OAGetErrorInfo @steps_handle
    	GOTO Destructor
    
    	END
    
    EXEC @resultcode = sp_OAGetProperty @steps_handle, 'Count', @steps_count OUTPUT
    IF @resultcode <> 0
    	BEGIN
    	print 'Unable to get number of steps'
            EXEC sp_OAGetErrorInfo @steps_handle
    	GOTO Destructor
    
    	END
    IF @debug_mode = 1
    	SELECT '#-steps: ' = @steps_count
    
    SELECT @result_sum = 0 --initialize
    WHILE @steps_count > 0 
    	BEGIN 
    	EXEC @resultcode = sp_OAGetProperty @steps_handle, 'Item', @step_handle OUTPUT, @steps_count
    	IF @resultcode <> 0
    		BEGIN
    		print 'Unable to get step'
                    EXEC sp_OAGetErrorInfo @steps_handle
    		GOTO Destructor
    
    		END
    
    	EXEC @resultcode = sp_OAGetProperty @step_handle, 'ExecutionResult', @step_result OUTPUT
    	IF @resultcode <> 0
    		BEGIN
    		print 'Unable to get ExecutionResult'
                    EXEC sp_OAGetErrorInfo @step_handle
    		GOTO Destructor
    
    		END
    	IF @debug_mode = 1
    		SELECT 'Step Handle' = @step_handle, 'Step #' = @steps_count, 'Step Result' = @step_result
    	IF @step_result <> 0
    		BEGIN
    		SELECT @resultcode = 0 --initialize
    		EXEC @resultcode = sp_OAMethod @step_handle, 'GetExecutionErrorInfo', @error_code OUT, @error_source OUT, @error_description OUT, @error_helpfile OUT, @error_helpcontext OUT, @error_interface_id OUT
    		SELECT 'GetExecutionErrorInfo: result code' = @resultcode, 'Error Code' = @error_code, 'Error Source' = @error_source, 'Error Desc' = @error_description
                    EXEC sp_OAGetErrorInfo @step_handle
    		END
    
    	SELECT @steps_count = @steps_count - 1
    	SELECT @result_sum = @result_sum + @step_result
    	END
    
    IF @result_sum > 0
    	print 'Package had ' + CAST(@result_sum as varchar) + ' failed step(s)'
    ELSE 
    	print 'Package Succeeded'
    
    --*************************************
    --clean up
    --*************************************
    Destructor:
    
    EXEC @resultcode = sp_OADestroy @package_handle
    EXEC @resultcode = sp_OADestroy @task_handle
    EXEC @resultcode = sp_OADestroy @property_handle
    EXEC @resultcode = sp_OADestroy @customtask_handle
    EXEC @resultcode = sp_OADestroy @message_handle
    
    SET NOCOUNT OFF
    GO
    					
  3. Run the stored procedure in Query Analyzer by supplying the queue name and the message body:
    EXEC send_msmq_message '.\Queue1', 'This is a test'

    Alternately, you can create a VBScript file that instantiates a MSMQ.MSMQMessage object and that sets the Body property directly.

    For example, you can create a file named Msmq.vbs by using the following code:
    if wscript.arguments.count < 1 then
      wscript.echo "Pass queue name as a command line param. Ex: "
      wscript.echo ""
      wscript.echo "  cscript msmq.vbs .\Queue1"
      wscript.quit(1)
    end if
    
    wscript.echo "Sending message to queue: " & wscript.arguments(0)
    set qinfo = createobject ("MSMQ.MSMQQueueInfo")
    qinfo.Pathname = wscript.arguments(0) '".\Queue1"
    set q = qinfo.open (2, 0)
    set msg = createobject ("MSMQ.MSMQMessage")
    msg.Priority = 1
    msg.label = "message label..."
    msg.body = "sent from MSMQMessage"
    msg.send q
    						
    In this example, the Message Queuing queue name is:
       .\Queue1
    						
    You can run this code by typing the following command from a command shell window:
    cscript msmq.vbs .\Queue1

STATUS

Microsoft has confirmed that this is a problem in the Microsoft products that are listed at the beginning of this article.

MORE INFORMATION

Steps to Reproduce the Problem

To demonstrate this problem, use the following script. This script creates a message queue and tries to set the property by using Transact-SQL:
DECLARE @hr int
DECLARE @MSMQQueueInfo int
DECLARE @MSMQQueue int
DECLARE @MSMQMessage int
DECLARE @src varchar(255)
DECLARE @desc varchar(255)

-- Create the MSMQQueueInfo object.
EXEC @hr = sp_OACreate 'MSMQ.MSMQQueueInfo', @MSMQQueueInfo OUT
IF @hr <> 0
BEGIN
   EXEC sp_OAGetErrorInfo @MSMQQueueInfo, @src OUT, @desc OUT 
   SELECT 
      'CreateObject MSMQQueueInfo' AS Operation, 
      hr=convert(varbinary(4),@hr), Source=@src, Description=@desc
   RETURN
END

-- Set MSMQQueueInfo.PathName to the name of the queue.
EXEC @hr = sp_OASetProperty @MSMQQueueInfo, 'PathName', ".\Queue1"
IF @hr <> 0
BEGIN
   EXEC sp_OAGetErrorInfo @MSMQQueueInfo, @src OUT, @desc OUT 
   SELECT 
      'Set MSMQQueueInfo.PathName' AS Operation, 
      hr=convert(varbinary(4),@hr), Source=@src, Description=@desc
   GOTO Destructor

END

-- Open the queue to get ref to MSMQQueue.
EXEC @hr = sp_OAMethod @MSMQQueueInfo, 'Open', @MSMQQueue OUTPUT, 2, 0
IF @hr <> 0
BEGIN
   EXEC sp_OAGetErrorInfo @MSMQQueueInfo, @src OUT, @desc OUT 
   SELECT 
      'MSMQQueueInfo.Open' AS Operation, 
      hr=convert(varbinary(4),@hr), Source=@src, Description=@desc
   GOTO Destructor

END


EXEC @hr = sp_OACreate 'MSMQ.MSMQMessage', @MSMQMessage OUT
IF @hr <> 0
BEGIN
   EXEC sp_OAGetErrorInfo @MSMQMessage , @src OUT, @desc OUT 
   SELECT 
      'CreateObject MSMQMessage' AS Operation, 
      hr=convert(varbinary(4),@hr), Source=@src, Description=@desc
   GOTO Destructor

END

EXEC @hr = sp_OASetProperty @MSMQMessage, 'Priority', 1
IF @hr <> 0
BEGIN
   EXEC sp_OAGetErrorInfo @MSMQMessage, @src OUT, @desc OUT 
   SELECT 
      'Set MSMQMessage.Priority' AS Operation, 
      hr=convert(varbinary(4),@hr), Source=@src, Description=@desc
   GOTO Destructor

END


EXEC @hr = sp_OASetProperty @MSMQMessage, 'Label', 'Sent from SQL server'
IF @hr <> 0
BEGIN
   EXEC sp_OAGetErrorInfo @MSMQMessage, @src OUT, @desc OUT 
   SELECT 
      'Set MSMQMessage.Label' AS Operation, 
      hr=convert(varbinary(4),@hr), Source=@src, Description=@desc
   GOTO Destructor

END


--
-- This block of code attempts to set the Body property
--
DECLARE @body varchar (30)
--DECLARE @body char(30)
--DECLARE @body nvarchar(30)
--DECLARE @body sql_variant
SELECT @body = 'This is the message body'
EXEC @hr = sp_OASetProperty @MSMQMessage, 'Body', @body
IF @hr <> 0
BEGIN
   EXEC sp_OAGetErrorInfo @MSMQMessage, @src OUT, @desc OUT 
   SELECT 
      'Set MSMQMessage.Body' AS Operation, 
      hr=convert(varbinary(4),@hr), Source=@src, Description=@desc
   GOTO Destructor

END
--
--
--


EXEC @hr = sp_OAMethod @MSMQMessage,'Send', NULL, @MSMQQueue
IF @hr <> 0
BEGIN
   EXEC sp_OAGetErrorInfo @MSMQMessage, @src OUT, @desc OUT 
   SELECT 
      'MSMQMessage.Send' AS Operation, 
      hr=convert(varbinary(4),@hr), Source=@src, Description=@desc
  GOTO Destructor

END

-- Destroy the object.
Destructor:

EXEC @hr = sp_OADestroy @MSMQQueueInfo
IF @hr <> 0
BEGIN
   EXEC sp_OAGetErrorInfo @MSMQQueueInfo, @src OUT, @desc OUT 
   SELECT hr=convert(varbinary(4),@hr), Source=@src, Description=@desc
   RETURN
END

EXEC @hr = sp_OADestroy @MSMQQueue
IF @hr <> 0
BEGIN
   EXEC sp_OAGetErrorInfo @MSMQQueue, @src OUT, @desc OUT 
   SELECT hr=convert(varbinary(4),@hr), Source=@src, Description=@desc
   RETURN
END

EXEC @hr = sp_OADestroy @MSMQMessage
IF @hr <> 0
BEGIN
   EXEC sp_OAGetErrorInfo @MSMQMessage, @src OUT, @desc OUT 
   SELECT hr=convert(varbinary(4),@hr), Source=@src, Description=@desc
   RETURN
END
				

Modification Type:MajorLast Reviewed:10/3/2003
Keywords:kbBug kbpending KB309002 kbAudDeveloper